Spliit is a free and open source alternative to Splitwise. You can either use the official instance at Spliit.app, or deploy your own instance:
Features
- Create a group and share it with friends
- Create expenses with description
- Display group balances
- Create reimbursement expenses
- Progressive Web App
- Select all/no participant for expenses
- Split expenses unevenly (#6)
- Mark a group as favorite (#29)
- Tell the application who you are when opening a group (#7)
- Assign a category to expenses (#35)
- Search for expenses in a group (#51)
- Upload and attach images to expenses (#63)
- Create expense by scanning a receipt (#23)
Possible incoming features
Stack
- Next.js for the web application
- TailwindCSS for the styling
- shadcn/UI for the UI components
- Prisma to access the database
- Vercel for hosting (application and database)
Contribute
The project is open to contributions. Feel free to open an issue or even a pull-request! Join the discussion in the Spliit Discord server.
Contribute financially
Spliit is free, open source, and has no ads. Hosting, database and API costs are paid for by donations. If you want to help keep it that way, you can:
- 🧡 Support us on Open Collective — recurring or one-time, with a public and transparent ledger of what comes in and what it is spent on, or
- 💜 Sponsor me (Sebastien).
Contributions of any size are appreciated, and so is simply telling people about the project.
Translation
The project's translations are managed using our Weblate project. You can easily add missing translations to the project or even add a new language! Here is the current state of translation:
Run locally
- Clone the repository (or fork it if you intend to contribute)
- Start a PostgreSQL server. You can run
./scripts/start-local-db.shif you don’t have a server already. - Copy the file
.env.exampleas.env - Run
npm installto install dependencies. This will also apply database migrations and update Prisma Client. - Run
npm run devto start the development server
End-to-end tests
The Playwright suite in e2e/ drives a real browser against the app running in
Docker, so it exercises the same image users deploy. It needs Docker and a free
port 3000, and nothing else — the stack builds itself from your checkout and
throws its database away afterwards.
npm run e2e
That builds the image, starts app + PostgreSQL from compose.e2e.yaml, waits
for /api/health/readiness, runs the suite and tears everything down. It never
touches your development stack or ./postgres-data.
While writing tests it is quicker to keep the stack up:
npm run e2e:up # build and start, then leave it running
npm run e2e:test -- --ui # iterate (also --headed, --grep, --debug)
npm run e2e:report # open the HTML report of the last run
npm run e2e:down # stop and delete the test database
--ui opens Playwright's UI mode, where you can pick tests, watch them run and
step through a trace. It does not start the stack itself, so run npm run e2e:up
first.
If port 3000 is already taken — by npm run dev, for instance — set
E2E_HOST_PORT on every command of the session, including the test run:
E2E_HOST_PORT=3100 npm run e2e # one-shot
E2E_HOST_PORT=3100 npm run e2e:up # or, for the iteration loop
E2E_HOST_PORT=3100 npm run e2e:test -- --ui
E2E_HOST_PORT=3100 npm run e2e:down
The same suite runs in GitHub Actions from the E2E workflow, which can be triggered manually and runs automatically on release tags.
Run in a container
- Run
npm run build-imageto build the docker image from the Dockerfile - Copy the file
container.env.exampleascontainer.env - Run
npm run start-containerto start the postgres and the spliit2 containers - You can access the app by browsing to http://localhost:3000
Run with Docker compose
This is a sample docker-compose.yml file that you can use to deploy this web app.
name: spliit
services:
app:
image: ghcr.io/spliit-app/spliit:latest
user: "1000:1000" # change to your user id or remove if you want root
ports:
- "8080:3000/tcp"
environment:
POSTGRES_PRISMA_URL: postgresql://spliit:spliit@database:5432/spliit
POSTGRES_URL_NON_POOLING: postgresql://spliit:spliit@database:5432/spliit
volumes:
- ./app/cache:/usr/app/.next/cache
depends_on:
- database
networks:
- spliit
database:
image: postgres:17.3
user: "1000:1000" # same as above
environment:
POSTGRES_USER: spliit
POSTGRES_PASSWORD: spliit
POSTGRES_DB: spliit
volumes:
- ./database/data:/var/lib/postgresql/data
networks:
- spliit
networks:
spliit:
The web app will then be available on your host at http://localhost:8080/.
You can use named volumes in place of bind mounts if you prefer not having data stored inside local directories.
Health check
The application has a health check endpoint that can be used to check if the application is running and if the database is accessible.
GET /api/health/readinessorGET /api/health- Check if the application is ready to serve requests, including database connectivity.GET /api/health/liveness- Check if the application is running, but not necessarily ready to serve requests.
Configuration
Every variable below is read at runtime. For a container deployment, set them in
container.env or pass them with docker run -e; no rebuild is required, which
means the published image can be configured by whoever runs it.
Application URL
Set BASE_URL to the public URL your instance is reachable at. It is used for
metadata, the sitemap, robots.txt, and to accept server actions sent to that
host.
BASE_URL=https://spliit.example.com
Defaults to http://localhost:3000.
Default currency
Set DEFAULT_CURRENCY_CODE to pre-select a currency on the new-group form.
DEFAULT_CURRENCY_CODE=EUR
Defaults to USD.
Migrating from the NEXT_PUBLIC_* variables
Earlier versions used NEXT_PUBLIC_-prefixed variables for the settings above
and for the opt-in feature flags below. Next.js inlines those into the app at
build time, so in a prebuilt image — like the published one — they are frozen
at whatever the release build used and setting them at runtime does nothing. The
runtime variables replace them:
| Old (build-time) | New (runtime) |
|---|---|
NEXT_PUBLIC_BASE_URL |
BASE_URL |
NEXT_PUBLIC_DEFAULT_CURRENCY_CODE |
DEFAULT_CURRENCY_CODE |
NEXT_PUBLIC_ENABLE_EXPENSE_DOCUMENTS |
ENABLE_EXPENSE_DOCUMENTS |
NEXT_PUBLIC_ENABLE_RECEIPT_EXTRACT |
ENABLE_RECEIPT_EXTRACT |
NEXT_PUBLIC_ENABLE_CATEGORY_EXTRACT |
ENABLE_CATEGORY_EXTRACT |
The old variables still work — the runtime variant simply takes precedence
when both are set, so there is nothing you have to change immediately. They
remain the right choice if you build your own image and want a setting baked in.
To migrate, drop the NEXT_PUBLIC_ prefix and set the variable wherever your
container gets its environment.
Opt-in features
Expense documents
Spliit offers users to upload images (to an AWS S3 bucket) and attach them to expenses. To enable this feature:
- Follow the instructions
