Skip to content
selfhostitPublic

Repository files navigation

Splitwiz, a grumpy little wizard holding back a river of euro bills with his staff

Splitwiz

Meet Splitwiz, the wizard who splits your costs. He stands in the river of receipts and bills so the two of you don't have to. Let Splitwiz take care of the money; you take care of each other.

Split shared expenses with your partner or roommate, on a server you own.

A small, self-hosted alternative to Splitwise for two people. No ads, no daily limits, no account on someone else's cloud. One Docker container, installable on your phone like a native app.

CI License: MIT Docker image Buy me a coffee

Splitwiz on a phone: balance, adding an expense, stats, expense detail with a category chart, and settings in dark mode

Why Splitwiz

  • Your data stays home. Everything lives in one SQLite file on your own machine: a NAS, a home server, a Raspberry Pi-class box or a cheap VPS.
  • Fast to use. Adding an expense is an amount, a description and one tap. The balance is the first thing you see.
  • Leaving Splitwise is easy. Import a group's CSV export and you land on the same balance, with every expense and payment kept.
  • Tiny to run. One container, about 30 MB of memory at rest, no external database.

Features

  • Add an expense in a few taps: amount, what it was for, who paid, and how to split it (50/50, percentage, exact amount, or "the other person owes all").
  • Sums in the amount field: type 12.50+8.30 or 90/3 (there are + − × ÷ keys above the keyboard) and Splitwiz works out the amount.
  • Quick add: the expenses you add most often show up as one-tap chips, and typing a past description fills in who paid, the split and the category from last time.
  • One balance on the home screen: who owes whom, and how much.
  • See what's new: Home tells you what the other person added, changed or commented on since you last looked ("Sam added 2 and changed 1"), with a dot on each of those rows until you tap Mark as seen.
  • Settle up with one tap, in full or in part.
  • History grouped by month, with search and filters (type, who paid, category, amount). Export just what you filtered as CSV. Swipe a row left to edit or delete it.
  • Undo instead of "Are you sure?": deleting anything shows an Undo bar for a few seconds.
  • Works offline: the app opens with the last data loaded, and expenses, payments and comments added without a connection are saved on the phone and sync once the server is reachable.
  • Tags for trips and events: tag expenses with something like #lisbon-2026 (recent tags are one tap away), then filter History by the tag to see what it cost in total, who paid what, and who owes whom for it alone. Tags carry over to repeating expenses and the CSV export.
  • Comments on expenses: both of you can leave comments on any expense, like a small chat thread. A comment typed while adding an expense becomes the first one.
  • Push notifications straight from your server, no account or extra app needed. Turn them on per phone under Settings > Notifications to hear when the other person adds or changes an expense or comments, when a repeating expense is added, and once a month when spending is heading over the budget. Tapping one opens that expense.
  • Repeating expenses (weekly, monthly, yearly) are added automatically on their day, and caught up if the server was off. A repeating expense can stop on a date (or after a number of times) and change amount over time, e.g. €80 until February, then €95; a timeline shows each amount phase and what it all adds up to. Any expense can be turned into a repeating one, and Settings suggests charges that already look monthly ("These look monthly"), for example right after an import.
  • Coming up on the home screen lists the repeating expenses due in the next 30 days or 3 months, with their total, so nothing arrives as a surprise.
  • Monthly budget shared by both of you. Stats shows this month's spending against it and where the month is heading: everyday spending is projected with a simple linear trend and the repeating expenses still due are added on their day.
  • Rules fill in a new expense from its description: anything with "Delhaize" is Groceries, 50/50; "Netflix" is paid by you and the other person owes all. Set them up under Settings > Rules.
  • Categories are yours to manage under Settings: add, rename, reorder, change the emoji, or delete. Each one can have its own monthly limit; Stats shows what's left and you both get a notification at 90%.
  • Stats for this month, last month, 3 or 12 months, this year or all time: total spent, spending per month with a dashed average line, a breakdown by category (with who paid what in each) you can drill into, and the biggest expenses.
  • Category trend on every expense: open an expense to see what you spent in its category over the last three months.
  • Import a bank statement: pick a CSV export of your account or card under Settings. Splitwiz guesses the columns and date format (you can correct them), lists the payments out, ticks the ones a rule matches, and flags ones that look added already. Tick what you shared and import; importing the same file again skips what's already in.
  • Import from Splitwise: pick a group's CSV export under Settings. Importing the same file again only adds new rows.
  • Live sync between both phones, light and dark mode, and a CSV export of everything.
  • Installable web app (PWA) for Android and iOS, with its own home-screen icon. Long-press the icon for Add expense and Settle up shortcuts.
Home screen with the balance and recent expenses Adding an expense with split and repeat options Stats tab with spending per month and per category History grouped by month with search

Quick start

Never heard of Docker? Follow the step-by-step guide for non-technical people: a Windows PC, Mac, Linux computer or Raspberry Pi at home, all by clicking and pasting.

Otherwise you need Docker. Pick whichever fits your machine; both end at the same place.

With a terminal (Linux server, VPS, Raspberry Pi, or a NAS with SSH):

curl -fsSL https://raw.githubusercontent.com/selfhostit/splitwiz/main/scripts/install.sh | sh

It asks for an install folder, your time zone and who may connect (Enter keeps each default), then starts Splitwiz and prints the address to open.

Without a terminal (a NAS's Docker app, Portainer, or any Compose tool): use docker-compose.yml as it is, or with a .env next to it (see .env.example). From a shell that is:

mkdir splitwiz && cd splitwiz
curl -O https://raw.githubusercontent.com/selfhostit/splitwiz/main/docker-compose.yml
docker compose up -d

Then open Splitwiz (http://localhost:8090 on the same machine) and add the two people on the setup screen. The first person also becomes the admin for the admin page at /_/. That's the whole setup: there are no sign-ups, so these are the only two accounts.

The setup screen asks for a one-time setup code, so nobody who stumbles on a fresh install can add themselves. The installer shows the code, and Splitwiz prints it to its log (docker logs splitwiz) until setup is done.

Prefer plain docker run?
docker run -d --name splitwiz --restart always \
  -p 127.0.0.1:8090:8090 -v "$PWD/pb_data:/app/pb_data" -e TZ=Europe/Brussels \
  ghcr.io/selfhostit/splitwiz:latest

Settings

All optional, in .env next to docker-compose.yml (the installer writes it for you):

Setting Default What it does
TZ UTC Your time zone, e.g. Europe/Brussels. Decides when repeating expenses are added and when the nightly backup runs.
SPLITWIZ_LISTEN 127.0.0.1 127.0.0.1: only this machine and a reverse proxy on it can connect. 0.0.0.0: every device on your network can; on a VPS or cloud server that means the whole internet, over plain http, because Docker opens the port even when a firewall such as ufw blocks it.
SPLITWIZ_PORT 8090 The port on this machine. On a new install the installer takes the next free one if another app has 8090.
SPLITWIZ_DATA ./pb_data Where the database, backups and push key live.
SPLITWIZ_VERSION latest Image tag: latest is the newest release, 1 every 1.x, 1.2.0 one release, edge follows main, and a commit SHA pins one build.
SPLITWIZ_PUSH_CONTACT Optional mailto: or https: address push services can contact.

Using it from your phones

Phones need to reach Splitwiz over HTTPS to install it as an app and to get notifications. Plain http:// on your home network works in a browser, but not for those two. Any of these gives you HTTPS; point it at http://127.0.0.1:8090:

  • Your NAS's own reverse proxy with its free certificate: Synology (see the guide), QNAP, or Unraid and TrueNAS with an Nginx Proxy Manager container.

  • Caddy on a server with a domain name. This is the whole config:

    splitwiz.example.com {
        reverse_proxy 127.0.0.1:8090
    }
    
  • Tailscale if you'd rather not open your router: tailscale serve --bg 8090 gives an HTTPS address that only your own devices can reach.

  • A Cloudflare Tunnel, Traefik or Nginx Proxy Manager work just as well.

Then open the address on each phone, sign in, and choose ⋮ > Install app in Chrome on Android or Share > Add to Home Screen (iOS/Safari).

Step-by-step guides

Where it runs

  • Should work on anything that runs Docker containers for linux/amd64, linux/arm64 or linux/arm/v7. That covers x86 and ARM servers and VPSes, Raspberry Pi 2 and newer (not the Pi Zero or Pi 1), and NAS systems with a Docker app: Synology (Container Manager), QNAP (Container Station), Unraid, TrueNAS SCALE, OpenMediaVault, Asustor and UGREEN, plus dashboards like Portainer and CasaOS that accept a Compose file.
  • Won't work on NAS models without Docker support (many budget and older models), or hosts without containers at all. Splitwiz is not yet listed in NAS app stores, so on those you paste the Compose file yourself.

Updating

Run the installer again, or:

docker compose pull && docker compose up -d

Updates bring the newest release: a release tag publishes latest, and what changed is in CHANGELOG.md. Every push to main publishes edge, if you'd like to follow it (SPLITWIZ_VERSION=edge). Your data and settings stay in pb_data and .env, and database migrations run on start.

Every image has a signed attestation of the workflow and commit that built it. Check one with the GitHub CLI:

gh attestation verify oci://ghcr.io/selfhostit/splitwiz:latest --repo selfhostit/splitwiz

To release: add the changes under a new version in CHANGELOG.md and web/package.json, merge, then publish a GitHub release tagged vX.Y.Z with the changelog entry as its notes. CI tests it, publishes the image and attests it.

Backups

  • Splitwiz makes a backup every evening at 20:00 (in your TZ) into pb_data/backups and keeps the last 7. You can change this in the admin page under Settings > Backups.
  • Copy the pb_data folder somewhere else from time to time to keep a backup off the machine.
  • Settings > Export all data (CSV) in the app gives you a human-readable copy.

Good to know

  • Splitwiz is built for exactly two people sharing costs, such as a couple or two roommates. It does not do groups.
  • Amounts are shown in euros for now.
  • Notifications need the app installed (on iPhone: added to the Home Screen, iOS 16.4 or newer) and the server able to reach the internet, since they are delivered through Apple's and Google's push services. The key that signs them is created on first use in pb_data/push_keys.json; if it is lost, turn notifications on again on each phone. In Brave, also turn on "Use Google services for push messaging" under brave://settings/privacy and restart Brave; it is off by default.

How it is built

Part Choice
Backend PocketBase used as a Go framework (backend/), SQLite database
Money logic backend/ledger: integer cents, split, balance and repeat-date rules, unit tested
Splitwise import backend/splitwise: parses the export and keeps each row's exact split
Web app Svelte 5, Vite and Tailwind (web/), installable PWA
Packaging One Docker image (Dockerfile) for x86-64 and ARM, published to ghcr.io/selfhostit/splitwiz by GitHub Actions

The server computes what each person owes for every expense itself, so a phone can never store an inconsistent split.

Development

# backend (needs Go 1.27+)
cd backend
go run . superuser upsert admin@example.com changeme123
go run . serve            # http://127.0.0.1:8090, admin at /_/

# web app with hot reload (needs Node 22+), in another terminal
cd web
npm install
npm run dev               # proxies /api to :8090

Tests: cd backend && go test ./... and cd web && npm test && npm run check.

scripts/deploy-to-nas.sh user@host builds the image on your computer and replaces the running container on a NAS over SSH (in /volume1/docker/splitwiz, or SPLITWIZ_DIR), for when you want to try a change before pushing it.

Security and maintenance

  • Not on the internet: the container listens on 127.0.0.1 only, and the installer warns when this machine has a public IP address. Reach it through Tailscale or your own reverse proxy with HTTPS.
  • Locked-down container: it drops every Linux capability and can't gain new ones.
  • Nobody claims a new install before you: the first account needs the one-time setup code the install prints (backend/app/setup.go).
  • Sign-ins are rate limited, and the web app sends a Content Security Policy (backend/app/headers.go).
  • Tested on every change: Go and web tests (balances, splits, CSV and Splitwise import) in CI, with Actions pinned to commit hashes.
  • Versioned releases: installs update to a release, not to every change on main, and every image has a signed attestation of the commit that built it (Updating).
  • No analytics or tracking. The data stays in pb_data on your machine; export all of it as CSV from Settings.

Found a security problem? Please write to kalfasyan@pm.me rather than opening an issue (security policy). Security and privacy covers every selfhostit app: what protects an install, what you are trusting and what is not done yet.

Contributing

Issues and pull requests are welcome. Please run the tests above before opening a pull request; CI runs the same checks.

Support

Splitwiz is free and stays free. If it saves the two of you some hassle, you can buy me a coffee ☕

License

MIT

Releases

Packages

Used by

Contributors

Languages