Self-hosted, single-user personal finance. Your banks, your budgets, your server.
Foxledger connects to your European bank accounts, keeps a local ledger of every transaction, categorizes them automatically (rules + a learning classifier + optional AI), tracks cash, detects recurring payments & subscriptions, and manages monthly budgets with alerts and an AI budget planner.
Everything runs on your own machine. Bank credentials never leave your server, API keys are encrypted at rest, and the app is protected by a master password with optional TOTP two-factor auth.
- Bank sync - connect banks via Enable Banking (thousands of EU banks, PSD2) and bunq directly
- Transactions - search, filter, sort, bulk review, CSV export, income/expense/net statistics
- Auto-categorization - German-first keyword heuristics, user-defined rules, and a naive-Bayes classifier that learns from your corrections
- AI (optional) - spending insights, one-click AI categorization, and an AI budget planner via OpenRouter (works with free models)
- Budgets - monthly limits per category or overall, progress bars with month markers, configurable alert thresholds, end-of-month spend projections
- Recurring & subscriptions - automatic detection of recurring payments with subscription flagging and monthly cost totals
- Cash wallet - manual cash entries with reconciliation
- Dashboard - net worth, balance history, category breakdowns, budget alerts, AI insights
- Security - master password (argon2), TOTP 2FA, encrypted sessions, CSRF protection, AES-256-GCM encryption for stored provider keys
| Dashboard | Transactions |
|---|---|
![]() |
![]() |
| Accounts | Rules |
|---|---|
![]() |
![]() |
git clone https://github.com/you/foxledger.git
cd foxledger
cp .env.example .envEdit .env:
- Set a strong
POSTGRES_PASSWORD(and mirror it inDATABASE_URL, using hostpostgres) - Generate secrets:
openssl rand -hex 32 # ENCRYPTION_KEY openssl rand -hex 32 # SESSION_SECRET
- Optionally fill in bank / AI provider keys (see below - you can also add them later)
Then:
docker compose up -d --buildOpen http://localhost:3000, create your master password, and you're in. Database migrations run automatically on startup.
Requirements: Node.js 20+, PostgreSQL 16+.
npm install
cp .env.example .env # configure as above, DATABASE_URL pointing at localhost
npx prisma migrate deploy
npm run db:seed # seeds default categories & categorization rules
npm run dev # or: npm run build && npm start- Create an account at enablebanking.com and register an application
- Generate an RSA key pair; upload the public key, save the private key as
enablebanking.pemin the project root - Set
ENABLE_BANKING_APP_ID,ENABLE_BANKING_API_KEY,ENABLE_BANKING_PRIVATE_KEY_PATH - Set
ENABLE_BANKING_CALLBACK_URLto a publicly reachable HTTPS URL ending in/api/integrations/enable-banking/callbackand register the same URL in the Enable Banking dashboard - Connect your bank under Integrations in the app
Create an API key in the bunq app (Profile β Security & Settings β Developers) and set BUNQ_API_KEY.
Set OPENROUTER_API_KEY (free tier available at openrouter.ai). This enables:
- AI Insights on the dashboard
- AI Categorize for transactions needing review
- AI Budget Planner - describe a savings goal, get a realistic per-category budget plan based on your last 3 months of spending
Without a key, all other features work normally.
- Next.js 15 (App Router) - UI and API routes in one deployable app
- PostgreSQL + Prisma - all data stays in your database
- Single-user by design - one master password, no accounts, no telemetry
- Provider API keys and session tokens are encrypted with AES-256-GCM (
ENCRYPTION_KEY) - Master password is hashed with argon2id; optional TOTP 2FA
- All mutating API routes require a CSRF token
- Never commit
.envorenablebanking.pem- both are gitignored
MIT



