Skip to content
woza.ink
← Blog
5 min read

Local-First Web Apps with Dexie and DexieCloud

Your app should work without the internet. Here's how to build local-first web apps using IndexedDB, Dexie.js, and DexieCloud for seamless sync.

On this page
  1. Why we should care (short and spicy)
  2. What does "local-first" actually mean?
  3. IndexedDB: the browser's built-in DB (and why it's awkward)
  4. Dexie.js: IndexedDB for humans
  5. Building a local-first app (pattern)
  6. DexieCloud: Sync without building a backend
  7. Trade-offs (read this before you commit to local-first)
  8. UX advice (tiny but powerful)
  9. When local-first is a great fit
  10. TL;DR — The Funky Summary
  11. Further reading

🚀 Quick punch: Build apps that keep working when the internet ghosts you. Local-first means the device is the source of truth — the cloud is just the nice-to-have sync smoothie.

TL;DR

  • Use the browser's IndexedDB for offline-first storage.
  • Dexie.js gives you a delightful, promise-based API over IndexedDB.
  • DexieCloud adds low-friction two-way sync so your users' data follows them — without you hosting a backend.
  • Start local-first, add sync later. Instant UI, offline resilience, better data ownership.

Why we should care (short and spicy)

If your app "spins and dies" when the network hiccups, users get annoyed, uninstall, and never come back. Local-first gives you instant reads and writes, full offline use, and background sync between devices. It's like building a native app, but with web tech — and users own their data.

Pro tip: ship the simplest local UX first. Sync is an add-on, not a requirement.


What does "local-first" actually mean?

Short answer: the device is the source of truth. Your UI talks to a local DB.1 Writes are instant. Sync happens in the background. The cloud is an eventually-consistent replica, not the gatekeeper.

Benefits:

  • Instant UI feedback — no network wait.
  • Works offline reliably.2
  • Users retain control of their data.
  • Easier to reason about UX (no loading spinners everywhere).

Trade-offs exist (storage limits, conflict resolution), but we'll cover those.


IndexedDB: the browser's built-in DB (and why it's awkward)

IndexedDB is powerful — transactional, supports indexes, stores blobs, and can hold lots of data. It's also famously... verbose.

Example (raw IndexedDB, because you deserve to cringe once in your life):

const request = indexedDB.open("MyDatabase", 1);
request.onupgradeneeded = (event) => {
  const db = event.target.result;
  const store = db.createObjectStore("tasks", { keyPath: "id" });
  store.createIndex("status", "status");
};
request.onsuccess = (event) => {
  const db = event.target.result;
  const tx = db.transaction("tasks", "readwrite");
  tx.objectStore("tasks").add({ id: 1, title: "Buy milk", status: "todo" });
};

Yes. That. Dexie saves you from writing this nonsense every time.


Dexie.js: IndexedDB for humans

Dexie wraps IndexedDB in a friendly, promise-based API3. Schema migrations, queries, transactions — all nicer. If you know ORMs, Dexie will feel familiar. If you don't, it's still delightful.

Minimal Dexie setup:

import Dexie from "dexie";

const db = new Dexie("TaskManager");
db.version(1).stores({
  tasks: "++id, status, project, dueDate",
  projects: "++id, name",
});

// Add a task
await db.tasks.add({ title: "Buy milk", status: "todo", date: new Date() });

// Query
const todos = await db.tasks.where("status").equals("todo").toArray();

Nice. No callback hell. No transaction voodoo.

Callout — Dexie is great because:

  • It normalizes the weirdness of IndexedDB.
  • It supports versioning and migrations.
  • It gives you fluent queries and async/await ergonomics.

Building a local-first app (pattern)

Design pattern checklist:

  1. Make IndexedDB (Dexie) your primary data source.
  2. Have your UI read/write directly to Dexie.
  3. Reflect local changes in the UI immediately.
  4. Sync to the cloud in the background (DexieCloud or custom sync)4.
  5. Handle conflicts thoughtfully (merge strategies, last-write-wins, or CRDTs if needed)5.

Architecture sketch:

User Action → Local IndexedDB (Dexie) — UI updates immediately → Background Sync (DexieCloud) → Cloud DB → Other devices pull changes


DexieCloud: Sync without building a backend

DexieCloud plugs into your Dexie DB and handles two-way sync, auth, access control, and conflict resolution6. For many apps it's "good enough" out of the box:

  • Two-way sync: local ↔ cloud
  • Built-in auth: simple email/OTP flows
  • Access control: share data securely
  • Conflict resolution: property-level merges and sensible defaults
  • Service worker support for background sync on supported browsers

Setup sketch:

import Dexie from "dexie";
import dexieCloud from "dexie-cloud-addon";

const db = new Dexie("TaskManager", { addons: [dexieCloud] });
db.version(1).stores({
  tasks: "++id, status, project, dueDate",
  projects: "++id, name",
});

db.cloud.configure({
  databaseUrl: "https://your-db-id.dexie.cloud",
  requireAuth: true,
});

One line summary: your Dexie code keeps working. DexieCloud sneaks in and makes it sync.


Trade-offs (read this before you commit to local-first)

  • Storage limits: Chrome is generous; Safari can be pruney.7 Consider prompting users to install your PWA to get better storage guarantees.
  • Conflict resolution: DexieCloud does last-write-wins at property level by default. For complex domains, design merge logic or use CRDTs.
  • Initial sync size: syncing millions of records to a client is unrealistic. Keep per-user datasets reasonable.
  • Pricing & hosting: DexieCloud has free tiers and pricing; self-hosting is an option if you need full control.

UX advice (tiny but powerful)

  • Show instant changes. Let sync be invisible.
  • Surface sync status unobtrusively (e.g., a tiny cloud icon with subtle state).
  • For destructive actions, consider local undo that syncs cancellation.
  • If conflicts happen, prefer automatic merges and only show UI when manual resolution is required.

When local-first is a great fit

  • Personal tools: notes, journals, habit trackers8
  • Productivity apps: task managers, timers, editors
  • Field work: apps used offline in the wild (surveys, inspections)
  • Privacy-first apps: users own their data

Not ideal when the server must be the sole authority (banking ledgers, some legal workflows) or when real-time collaborative CRDT-level sync is the requirement.


TL;DR — The Funky Summary

  • Build your app so it works with no network. The device is the source of truth.
  • Use Dexie to make IndexedDB pleasant to work with.
  • Add DexieCloud when you want simple, reliable sync without managing servers.
  • Start local, add sync later. Your users will forgive you for everything except slow, brittle apps.

Further reading

  • Dexie.js documentation — getting started guide with framework-specific examples
  • DexieCloud — the sync service; pricing, docs, and self-hosting options
  • Local-first Software — the original Ink & Switch essay that defined the term and the principles; still the best articulation of why this matters

Notes

  1. 1Source

    The term "local-first" was defined in the 2019 Ink & Switch paper Local-First Software: You Own Your Data, in Spite of the Cloud by Martin Kleppmann, Adam Wiggins, Peter van Hardenberg, and Mark McGranaghan. They identified seven ideals: (1) fast, (2) multi-device, (3) offline-capable, (4) collaborative, (5) long-lived, (6) private, and (7) user-owned. The paper remains the foundational reference for the movement.

    — Ink & Switch

    source →
  2. 2Context

    The local-first movement is accelerating. There is now a dedicated Local-First Conf (2026 edition), a FOSDEM track for "Local-First, sync engines, CRDTs," and growing adoption in production apps like Notion, Figma, and WhatsApp. About half of developers adopting local-first target offline-heavy use cases (field work, construction, mining); the other half focus on faster UIs for everyday apps.

    source →
  3. 3Context

    Dexie.js was created by David Fahlander in 2014 for a personal project. He open-sourced it because "it was so much more fun to put it out as open source." It has since grown to 12,000+ GitHub stars, 500,000+ weekly npm downloads, and adoption across 27,000+ repositories. Notable users include WhatsApp, GitHub, Microsoft To-Do, Wire, and Flightradar24.

    — David Fahlander

    source →
  4. 4Counter

    Kleppmann himself warns that CRDTs are "easy to implement badly" — many published algorithms have anomalies that cause strange behavior in edge cases, and naive implementations often have terrible performance. DexieCloud sidesteps this by using property-level last-write-wins by default, which is simpler but can lose concurrent edits to the same field.

    — Martin Kleppmann, *CRDTs: The Hard Parts*

    source →
  5. 5Source

    CRDTs (Conflict-free Replicated Data Types) are the key enabling technology behind local-first sync. Martin Kleppmann describes them as data structures that are "multi-user from the ground up while also being fundamentally local and private." His Automerge library implements a JSON CRDT that allows concurrent edits to automatically merge without conflicts — no central server required.

    — Martin Kleppmann

    source →
  6. 6Note

    DexieCloud's property-level merge strategy means that if two users edit different fields of the same record concurrently, both changes are preserved. If they edit the same field, last-write-wins applies. For most CRUD apps (task managers, notes, trackers) this is sufficient. For collaborative text editing or complex data structures, you'll want a full CRDT like Automerge or Yjs.

  7. 7Note

    Safari's storage behavior is the main cross-browser pain point. In non-PWA Safari, IndexedDB data can be evicted after 7 days of inactivity. Installing the app as a PWA (Add to Home Screen) lifts this restriction. Chrome is far more generous, typically allowing IndexedDB to use up to 80% of total disk space per origin.

  8. 8Quote

    From the Ink & Switch paper: "We believe that data ownership and real-time collaboration are not at odds with each other. It is possible to create software that has all the advantages of cloud apps, while also allowing you to retain full ownership of the data, documents, and files you create." This is the thesis that launched the local-first movement.

    — Kleppmann et al., Ink & Switch (2019)

    source →