DEV Community

Cover image for Why I Chose IndexedDB Over a Backend for My Finance App
MaxxMini
MaxxMini

Posted on • Edited on

Why I Chose IndexedDB Over a Backend for My Finance App

When I decided to build a personal finance app, the first question wasn't "which framework?" — it was "where does the data live?"

I'm a solo developer. I wanted to build something I'd actually use daily to track spending, budgets, and financial goals. But the thought of storing anyone's bank transactions, income details, and spending habits on my server? That felt wrong from the start.

So I made a deliberate choice: no backend. No database server. Everything stays in the browser via IndexedDB.

Here's how that went — the good, the bad, and what I'd tell you if you're considering the same approach.

The Problem: Financial Data Is Sensitive

Most finance apps want you to create an account, hand over your data, and trust that their server is secure. For a solo dev project, that's a huge responsibility:

  • You need authentication, encryption at rest, HTTPS everywhere
  • You're liable if there's a breach
  • You need ongoing server costs, even for a side project
  • GDPR/privacy compliance becomes your problem

I didn't want any of that. I wanted a tool that works like a calculator — you use it, your data stays with you, nobody else is involved.

Why IndexedDB (and Not the Alternatives)

localStorage was my first thought, but it caps out at ~5-10MB depending on the browser. For a finance app that might accumulate years of transaction data, that's a non-starter.

WebSQL is deprecated. Chrome still supports it, but it was removed from the web standards track years ago. Building on it would be technical debt from day one.

IndexedDB is the real deal:

  • Built into every modern browser
  • Can store hundreds of MB (browser-dependent, but typically 50%+ of available disk)
  • Supports indexes for fast queries
  • Transactional — ACID-compliant within the browser
  • No plugins, no dependencies on external services

The catch? The raw IndexedDB API is notoriously painful. It's callback-based, verbose, and feels like it was designed to discourage casual use.

Enter Dexie.js: Making IndexedDB Actually Usable

Dexie.js wraps IndexedDB with a clean, Promise-based API. It was the single best technical decision in this project.

Here's what my schema looks like:

const db = new Dexie('DonFlowDB');

db.version(1).stores({
  transactions: '++id, date, categoryId, type, amount',
  categories: '++id, name, type, color',
  budgets: '++id, categoryId, month, amount',
  settings: 'key'
});
Enter fullscreen mode Exit fullscreen mode

That's it. Four lines define my entire database schema with indexed fields. Compare that to setting up PostgreSQL, writing migrations, configuring an ORM, and deploying a server.

Why Dexie Over Raw IndexedDB

  • Promise-based: await db.transactions.where('date').between(start, end).toArray() — reads like English
  • Schema versioning: Built-in migration support. When I added the budgets table in v2, Dexie handled the upgrade automatically
  • Bulk operations: Adding 100 transactions in one call is trivial
  • Live queries (with Dexie's React hooks): useLiveQuery() gives you reactive data that updates the UI when the DB changes — no manual re-fetching

Migration Pattern

As the app evolved, I needed to add fields and tables. Dexie makes this straightforward:

db.version(1).stores({
  transactions: '++id, date, categoryId, type, amount',
  categories: '++id, name, type'
});

db.version(2).stores({
  transactions: '++id, date, categoryId, type, amount',
  categories: '++id, name, type, color',
  budgets: '++id, categoryId, month, amount'
});
Enter fullscreen mode Exit fullscreen mode

Each version builds on the last. Dexie detects the user's current version and runs upgrades sequentially. No migration scripts, no downtime.

The Tradeoffs (Honest Assessment)

I'm not going to pretend this approach is perfect. Here's what you give up:

1. No Cross-Device Sync (The Biggest Weakness)

This is the elephant in the room. If you add transactions on your laptop, they don't appear on your phone. Period.

I've considered workarounds — Dexie Cloud exists, CRDTs are fascinating — but for now, I use DonFlow on one device. For a personal tool, that's acceptable. For a product with users who expect multi-device sync? This approach doesn't work without significant additional infrastructure.

2. Browser Data Deletion Risk

If a user clears their browser data, or their browser profile gets corrupted, the data is gone. This is real and it's scary.

My mitigation: Export/Import functionality. Users can export all their data as a JSON file and import it back. It's manual, it's not automatic cloud backup, but it works. I also added a reminder prompt that periodically suggests exporting.

3. No Server-Side Analytics or Insights

I can't run queries across all users' data to find trends, improve the app, or offer personalized insights based on aggregate data. Everything is isolated per browser.

For a privacy-focused app, this is actually a feature, not a bug. But it limits what you can build.

4. Storage Limits Are Browser-Dependent

Firefox, Chrome, and Safari all have different storage policies. Safari is particularly aggressive about evicting data from sites you haven't visited recently (though this mainly affects non-PWA usage). I recommend users install DonFlow as a PWA for more persistent storage.

The Results

After months of development:

  • 155+ commits on the repo
  • ~4,700 lines of code (TypeScript + React)
  • Deployed on GitHub Pages — literally free hosting
  • Server cost: $0/month — forever
  • Zero data breaches possible — because I never have the data
  • Works offline — once loaded, no internet needed

The app handles transactions, categories with custom colors, monthly budgets, charts and analytics, data export/import, and a demo mode for people who want to try it without entering real data.

When This Approach Makes Sense

After living with this architecture for months, here's my honest take on when to use it:

Good fit:

  • Privacy is a genuine priority, not just marketing
  • Single-user or personal-use tools
  • Offline functionality is important
  • You want zero ongoing costs
  • You're a solo dev who doesn't want to manage infrastructure

Bad fit:

  • Users expect cross-device sync
  • You need server-side processing or ML on user data
  • Collaborative features are core to the product
  • You need admin access to user data for support

What I Learned

💡 Building on $0? I documented everything — tools, platforms, mistakes — in my free playbook.

Building DonFlow taught me that not every app needs a backend. We've been conditioned to think "real apps" need servers, databases, authentication systems, and DevOps pipelines. Sometimes the browser is enough.

IndexedDB with Dexie.js gave me a genuinely capable database that lives entirely in the user's browser. The DX is good, the performance is excellent, and the privacy story is unbeatable.

Is it the right choice for every project? Absolutely not. But for a personal finance tracker where privacy matters more than convenience? It was exactly right for me.


📚 More in this series

This article is part of Building a Finance App With No Server — building a complete finance app with zero backend costs.

  1. The Browser-Only Architecture — why I went serverless
  2. Zero AI, Zero Backend, Zero Tracking — the design philosophy
  3. Why I Chose IndexedDB ← you are here
  4. Share State via URL — No Backend Required — URL-based state management
  5. Coming next: How I Parse 14 Korean Bank CSV Formats in the Browser

📥 Building with $0? I documented everything in The $0 Developer Playbook — free, no signup.

Top comments (2)

Collapse
 
bhavin-allinonetools profile image
Bhavin Sheth

This is a solid use case for IndexedDB. I did something similar for a notes tool, and the biggest win was instant load and zero backend maintenance. One thing that helped a lot was adding simple auto-export reminders — users feel much safer knowing they have a backup. Dexie really makes this approach practical for real apps.

Collapse
 
maxxmini profile image
MaxxMini

The auto-export reminder idea is really smart — I actually implemented something similar. DonFlow shows a periodic nudge to export when the user hasn't backed up in a while. You're right that it dramatically reduces the anxiety around browser-only storage.

Dexie's useLiveQuery() hook was the other game-changer for me. Having reactive data without manual re-fetching means the UI always reflects the latest state, which is exactly what you'd expect from a backend-powered app but with zero server round-trips.

Curious about your notes tool — did you run into any issues with large text content in IndexedDB? I've seen some performance quirks with large blobs depending on the browser.