Not too long ago, I found myself in a Lisbon hotel room, staring at a project management app my team had poured four months into. The Wi-Fi was behaving like a mirage—connected but hopelessly broken. A blank screen with a spinner greeted me, followed by a timeout error. On my phone, with a shaky cellular tether, the app crawled—every click a two-second wait. This was a modern stack: React, Node, Postgres, Redis, a GraphQL API with six resolvers just for the task board. All that infrastructure, yet I couldn't see my own data without a round-trip to a server thousands of miles away. That night, I began exploring local-first architecture—not out of curiosity, but mortification.
At first, I dismissed local-first as academic fluff. When Ink & Switch published their "Local-First Software" paper in 2019, I thought it was interesting but impractical. Seven years and three production apps later, I've learned otherwise. I've also ripped local-first out of two projects where it was the wrong call. These are the hard-won lessons I want to share—written for seasoned developers who are understandably skeptical of silver bullets.
1. What Local-First Actually Means (And What It Doesn't)
I need to clear a persistent confusion: local-first is not offline-first. Offline-first gracefully handles network loss but keeps the server as the single source of truth. Cache-first strategies (like service workers) serve stale data faster, but they don't change who owns the data. PWAs are a delivery mechanism—installable, cached, with push notifications. None of these are data architectures.

Local-first is a data architecture. The user's device holds the primary copy of their data. The app reads and writes to a local database, rendering instantly, and syncs with servers in the background. The local copy is authoritative; the server is just another replica. This flips the traditional client-server relationship on its head.
2. The Seven Ideals That Started It All
The Ink & Switch paper outlined seven ideals for local-first software: fast, multi-device, offline, collaboration, longevity, privacy, and user ownership. When I first read them, they felt like a wish list, not engineering requirements. I was wrong to dismiss them.
These ideals aren't just nice-to-haves—they form a coherent vision for how software should work in a disconnected world. Fast means sub-100ms responses; multi-device means seamless sync; offline means full functionality without connectivity; collaboration means real-time conflict resolution; longevity means data survives the service; privacy means no unnecessary data on servers; user ownership means you control your data. Achieving all seven is difficult, but aiming for them shapes better architecture.
3. Why Offline-First Is Not Local-First
This confusion is rampant. I've heard conference talks conflate local-first with offline-first, and it's misleading. Offline-first treats the server as the truth, even if you cache locally. When the network returns, the server overwrites local changes. That's great for resilience, but it doesn't give users ownership of their data.
Local-first, by contrast, says the local database is the primary copy. The server is a sync peer. If a device is offline indefinitely, the user continues to work normally. This matters for applications like notebooks, task managers, or design tools where users expect their data to be available and modifiable anywhere, anytime, without depending on a cloud service's uptime.
4. The Real-World Wake-Up Call
My Lisbon hotel room was a perfect storm: unreliable network, a complex app, and a demo that failed spectacularly. That moment forced me to question everything I assumed about web architecture. We had built a production-grade SPA, but the user experience was fragile and slow when connectivity faltered.
After that, I built my first local-first prototype using CRDTs (Conflict-Free Replicated Data Types) for sync. The difference was night and day. Tasks appeared instantly. Moving columns felt like a native app. Offline? No problem—changes synced when I reconnected. For the first time, the app matched the paper's ideals. It wasn't easy—there were new challenges around conflict resolution and data migration—but the user experience was undeniably superior for that use case.

5. The Tooling Maturity Gap (2019 vs. 2026)
In 2019, local-first tooling was immature. I tried using Automerge and CRDTs for a simple collaborative editor, and it was a slog. Libraries were buggy, performance was poor with large datasets, and documentation was sparse. I abandoned the approach for that project.
Fast-forward to 2026: the ecosystem has matured significantly. Libraries like Yjs, Automerge 2.0, and Replicache offer production-grade CRDT implementations. IndexedDB, OPFS (Origin Private File System), and Web Locks have made local storage robust. Sync protocols are more standardized. The barrier to entry is lower, but it's still not trivial—expect to invest in learning conflict resolution and offline-first testing patterns.
6. When Local-First Is a Good Fit (And When It's Not)
From my experience, local-first shines for apps where users own and frequently modify personal data: note-taking apps, task managers, personal finance tools, design editors, or any application where offline availability is critical. Collaboration becomes a bonus—multiple users can edit the same document offline and merge conflicts later.
It's a poor fit for apps that depend on server-side validation, centralized rules (like banking transactions), or real-time consensus (like multiplayer games with shared state). It's also overkill for simple read-only content or apps where data is ephemeral. Every project that I ripped local-first out of fell into one of these categories: the complexity added no user benefit.
7. My Mistakes and Hard-Earned Advice
I've made two big mistakes. First, assuming local-first was automatically better. For a simple chat app, the overhead of conflict resolution and sync complexified everything without improving latency (since chat already works well over WebSocket). Second, underestimating data migration. When you upgrade schema on a local database, every device must migrate independently—and if a migration fails, the device is stuck. Server-side migrations are easier to control.
My advice: start small, prototype with a single feature, and measure the user experience. Use libraries like Yjs for collaboration, but don't roll your own sync protocol unless you have a dedicated team. And always consider if the seven ideals actually matter for your users. Local-first is powerful, but it demands respect for its complexity.
Conclusion: Local-first web development has matured from an academic curiosity to a practical architecture for certain applications. The hotel room that embarrassed me led to a deeper understanding of data ownership and user experience. In 2026, the tools are ready—but the question remains: is your app ready for the shift? If you're building a tool that users depend on offline, with personal data that should remain under their control, local-first might be your best bet. Just don't let the buzzwords fool you—it's a data architecture, not a silver bullet.