The Shrinking Monolith: Inside sayyedaaman2/expense-tracker
How a minimalist local-first finance app serves as a boilerplate for the zero-dependency database era using Express 5 and native Node.js SQLite.
- The native node:sqlite module eliminates the need for complex build chains and third-party database drivers in modern JavaScript applications.
- Hand-rolled dynamic SQL paired with strict Zod validation offers a type-safe, lightweight alternative to heavy ORM abstractions.
- Developers continue to reinvent personal finance tools to prioritize absolute data privacy and local-first performance over commercial SaaS features.
The Standard Library Absorbs the Database
For years, building a Node.js application with SQLite meant wrestling with native bindings, Python build chains, and node-gyp. The alternative was adopting a heavy ORM that abstracted the database away but added massive overhead to the node_modules folder.
The expense-tracker repository demonstrates a profound shift. By utilizing the new import { DatabaseSync } from 'node:sqlite', it bypasses the traditional dependency hell entirely. The standard library is now capable enough to handle persistent local storage without external drivers, resulting in a drastically lighter and faster installation process.
Bleeding Edge by Default
Beyond the database layer, this project serves as a time-capsule for the latest major version bumps across the JavaScript ecosystem. It wires together Express 5.1, which finally brings native Promise handling out of beta, alongside Tailwind CSS 4.0 and React 19.
Hand-Rolled SQL Meets Type Safety
Instead of relying on Prisma or Drizzle, the author eschews ORM magic for a manual dynamic SQL builder. Fields and values are pushed into arrays to construct raw UPDATE statements based precisely on the incoming payload.
if (payload.title !== undefined) {
fields.push("title = ?");
values.push(payload.title);
}
This raw approach is made safe by Zod, which acts as a strict bouncer at the network layer. It ensures that only validated, expected schema properties ever reach the SQL builder, marrying low-level database control with high-level type safety.
The Developer's Dilemma: Build vs. Host
Why do developers continually rebuild expense trackers? The motivation is rarely about lacking features in commercial tools; it is a rejection of latency and data-harvesting. The open-source personal finance space is driven by a desire for absolute data privacy and lightning-fast local data entry.
I wanted to create something that would be: Smart enough to give insights about our spending, Simple enough that we’d actually use it daily, Mobile-first (because who carries a laptop to record coffee expenses?), Lightning fast to use (under 5 seconds to add an expense)
| Project | Stack | Paradigm | Best For |
|---|---|---|---|
| expense-tracker | Node / Native SQLite | Barebones Monorepo-lite | Educational boilerplate, minimalists |
| Actual | Node / React | Local-first sync engine | Users wanting a polished offline experience |
| Firefly III | PHP / Laravel | Double-entry monolithic server | Power users needing complex instruments |