Why We Built an Offline-First Database (And Why You Might Need One Too)
We started building FFDB because we kept running into the same problem on client projects: users expect apps to work, even when their connection doesn't.
Not "work with limited features." Not "show a friendly error message." Just… work. Like a native app from 2010 that didn't need to phone home every time you tapped a button.
The problem with most BaaS platforms
Firebase is great. Supabase is great. AWS Amplify, PlanetScale, Convex—all great tools. But they share a fundamental assumption: you're online.
Sure, they have "offline support." But it's bolted on. It's an afterthought. You get:
- A local cache that expires
- Optimistic updates that sometimes fail silently
- Conflict resolution you have to handle yourself
- A confusing mental model where some data is "real" and some is "pending"
For a todo app, fine. For anything users rely on? You're building a house on sand.
What offline-first actually means
Offline-first doesn't mean "works offline sometimes." It means:
-
Local is the source of truth. Reads and writes hit IndexedDB (or SQLite, or whatever) instantly. No network round-trip. No loading spinners for data you already have.
-
Sync is automatic and invisible. When you're online, changes flow up. When your user's phone reconnects after going through a tunnel, changes flow down. The app doesn't care. The user doesn't notice.
-
Conflicts are resolved deterministically. Last-write-wins. Not "first to the server wins" or "whoever has the strongest WiFi wins." The most recent timestamp wins, and every client agrees on what "most recent" means.
What we built
FFDB gives you:
- Auth (email/password, OAuth, magic links)
- Database (document store, relational queries, full-text search)
- Blob storage (images, files, videos)
- Real-time sync (when online)
- Offline writes (always)
- Conflict resolution (last-write-wins, automatic)
And it works in any JavaScript environment. React. Vue. Svelte. Node. Deno. Bun. React Native. Doesn't matter.
Your code looks like this:
import { ffdb } from '@ffdb/client'
const db = ffdb('my-app')
// Write locally (instant)
await db.collection('tasks').insert({
title: 'Build the thing',
completed: false,
})
// Read locally (instant)
const tasks = await db.collection('tasks').find({ completed: false })
// Sync happens automatically when online
No spinners. No "pending" state. No retry logic. It just works.
When you actually need this
Not every app needs offline-first. If you're building:
- Internal dashboards that only run on corporate WiFi
- Admin panels where latency doesn't matter
- Anything read-only
…you probably don't need FFDB.
But if you're building:
- Mobile apps (spotty connections are the norm)
- Field service tools (techs in basements, warehouses, rural sites)
- Note-taking or creative tools (writers work on planes)
- Anything where "loading…" is friction
…you need offline-first. And you needed it yesterday.
Why we open-sourced the beta
We're using FFDB in production on client projects. It works. But we're keeping it in public beta because:
- We want feedback from people who aren't us
- We want to make sure the API is right before 1.0
- We believe this should exist in the world, whether or not it makes us money
If you're tired of building sync logic from scratch, or you're tired of telling users to "check their connection," give it a shot.
The free tier is generous. The paid tiers are cheap. And if you have questions, you can email me directly: sean@forever-frameworks.com.
Sean Cotter is the technical co-founder of Forever Frameworks. He's been writing software for 16 years and complaining about network latency for at least 12 of them.