Your favorite self-hosted finance tracker!
BetterTracker is a self-hosted, multi-user expense and income tracker. Manage multiple trackers with custom categories, payees, and recurring schedules. Share trackers publicly, monitor your finances with statistics and charts, and administrate users via a built-in admin panel with role-based permissions and audit logging.
Quick Start · Demo · GitHub Issues · Discord
| Feature | Description |
|---|---|
| Trackers | Multiple trackers with custom colors, currencies, and members |
| Transactions | Record income and expenses with categories and payees |
| Schedules | Recurring payment templates with flexible frequency settings |
| Statistics | Visual charts for monthly trends, category breakdowns, and more |
| Public Sharing | Share trackers publicly via a unique link with live statistics |
| Authentication | Email/password or custom OIDC provider |
| Admin Panel | User management, registration control, and audit logging |
| Roles | Superadmin, admin, and user roles with per-tracker permissions |
| Discord | Optional webhook notifications per tracker |
docker run -d \
-p 3000:3000 \
-v ./data:/app/data \
-e BETTER_AUTH_SECRET=$(openssl rand -base64 32) \
-e BETTER_AUTH_URL=http://localhost:3000 \
--name bettertracker \
ghcr.io/pantelx/bettertracker:latestOpen http://localhost:3000. The first registered user becomes superadmin.
git clone https://github.com/panteLx/BetterTracker.git
cd BetterTracker
cp .env.example .env
# Edit .env and set BETTER_AUTH_SECRET
docker compose up -dgit clone https://github.com/panteLx/BetterTracker.git
cd BetterTracker
npm install
cp .env.example .env
npm run db:migrate
npm run devBETTER_AUTH_SECRET= # openssl rand -base64 32
BETTER_AUTH_URL=http://localhost:3000
BETTER_AUTH_ALLOWED_HOSTS=localhost
BETTER_AUTH_TRUSTED_ORIGINS=http://localhost:3000OIDC_DISPLAY_NAME=OpenID Connect
OIDC_DISCOVERY_URL=https://sso.example.com/.well-known/openid-configuration
OIDC_CLIENT_ID=
OIDC_CLIENT_SECRET=
OIDC_SCOPES=openid,profile,emailDEFAULT_LOCALE=en-US # en-US or de-DE, used until a user picks a language
TZ=Europe/Berlin # used for date/time formattingSee .env.example for all options.
npm run db:migrate # Apply migrations
npm run db:generate # Generate migrations after schema changes
npm run db:studio # Open Drizzle Studio GUIMaintainers with push access can cut a release from a clean main with:
npm run release patch # 0.1.0 -> 0.1.1
npm run release minor # 0.1.0 -> 0.2.0
npm run release major # 0.1.0 -> 1.0.0This bumps package.json/package-lock.json, commits, tags, and pushes, then
creates a GitHub release with auto-generated notes. The pushed tag triggers
container.yml, which builds and
publishes the versioned Docker image. Requires the GitHub CLI
to be installed and authenticated (gh auth login).
Images are available at ghcr.io/pantelx/bettertracker:
| Tag | Description |
|---|---|
latest |
Latest stable release |
vX.Y.Z |
Specific version |
main |
Development build (unstable) |
| Layer | Technology |
|---|---|
| Framework | Next.js 16, React 19, TypeScript |
| Database | SQLite, Drizzle ORM |
| Auth | Better Auth |
| UI | Tailwind CSS, shadcn/ui, Radix UI |
| Charts | Recharts |
GitHub Issues · Buy Me a Coffee · GitHub Sponsors
MIT License. See LICENSE for details.



