Dutch is a full-stack expense-splitting PWA built for friends, flatmates, and travel groups. It lets you create shared expenses, split costs six ways, track balances, and settle up — all without a native app install.
Screenshots

Features
- Six split modes — equal, exact amounts, percentages, shares, itemised, and adjustment
- Groups — create named groups with emoji, add members, and track group-level balances
- Friends — bilateral friendship model with per-pair balance tracking and UPI deep links for payments
- Guest contacts — add people who don't have an account; they appear in splits and receive email notifications
- Expense media — attach photos and PDFs (receipts, invoices) to any expense via Cloudflare R2
- Email notifications — participants are emailed when an expense is created, edited, or deleted, with a full split breakdown
- Settlements — record payments between any two participants; balances update in real time
- Activity feed — full audit log of every expense, settlement, and membership change
- Offline-first — mutations queue to IndexedDB when offline and sync automatically on reconnect via Background Sync
- Installable PWA — add to home screen on iOS, Android, and desktop; works like a native app
Technical highlights
- Built with Next.js App Router — server components by default, client components only where needed
- Drizzle ORM on Neon serverless Postgres — type-safe queries, no magic
- Email OTP auth — no passwords, no OAuth; 6-digit codes via Resend, session tokens SHA-256 hashed in the DB
- IP-based rate limiting on all auth endpoints, full HTTP security headers (CSP, HSTS, X-Frame-Options)
- Offline queue — IndexedDB-backed mutation queue replays on reconnect; Background Sync fires even after the app is closed (Chrome/Android)
- Deployed on Vercel with edge middleware for auth