Home

Local First, Offline First, and Cloud

There are three ways to think about where your data lives: local first, offline first, and cloud only. They're not just technical decisions. They're statements about who owns the data, who controls the software, and what happens when the company behind it disappears.

I've been thinking about this a lot lately. Most of the software I build is cloud-based. But there's an ethical dimension to local-first that I find compelling, and a practical framework called Evolu that makes it surprisingly accessible.

Local First

Local-first means the data lives on your device. The app works without the internet. If you want to sync across devices, you can, but the sync is just replication. The canonical copy is yours.

This sounds obvious, but it's a radical departure from how most modern software works. Your notes app probably stores everything on someone else's server. Your recipe manager, your to-do list, your password manager. You're renting access to your own data.

Local-first is ethical. It's a statement that your software should outlive the company that wrote it. That your data should belong to you. That if I go out of business, you shouldn't lose twenty years of recipes or notes or documents.

The technical insight behind local-first is that most cloud functionality is just CRUD. Create, read, update, delete. Entity representation. If that's all your backend does, you don't need a backend. You need a sync protocol.

Evolu

Evolu is a framework that makes local-first practical. It's built on CRDTs (Conflict-free Replicated Data Types), which means multiple devices can edit the same data simultaneously and merge changes without conflicts.

The Evolu documentation explains the model:

typescript
import * as Evolu from "@evolu/common";

const TodoId = Evolu.id("Todo");

const Schema = {
  todo: {
    id: TodoId,
    title: Evolu.NonEmptyString100,
    isCompleted: Evolu.nullOr(Evolu.SqliteBoolean),
  },
};

You define a schema. You create an Evolu instance. You insert and update data locally. The sync happens automatically in the background. All data is end-to-end encrypted with a key derived from a mnemonic that only you know.

The beautiful part is the relay architecture. Evolu relays are stateless. They don't store your data. They just facilitate sync between your devices. You can run your own relay, use Evolu's free one, or use multiple relays simultaneously for redundancy. The relays don't need to sync with each other. Your devices sync them eventually.

typescript
const evolu = createEvolu(evoluReactWebDeps)(Schema, {
  name: SimpleName.orThrow("your-app-name"),
  transports: [{ type: "WebSocket", url: "wss://your-relay-url" }],
});

If the relay goes down, your app still works. If you switch relays, your data comes with you. If the company behind Evolu disappears, you can run your own relay or use anyone else's. The protocol is documented and open.

What Local First Isn't

Some functionality genuinely requires a server. Authentication against third-party providers. Sending emails. Processing payments. Generating AI responses. These things can't happen on your device alone.

Local-first doesn't mean no server. It means the core application state lives on your device, and server interactions are additive rather than essential. The app works without them. They just make it better.

The Pretenders

A lot of tools marketed as "local-first" are actually just offline-first with aggressive caching. TanStack Query with persistence. Service workers that cache API responses. IndexedDB as a read-through cache.

The difference is ownership. If the cache is just a performance optimisation for cloud data, you're still dependent on the cloud. If the server disappears, the cache eventually becomes stale and useless. That's not local-first. That's offline-first with better UX.

True local-first means the local copy is authoritative. The cloud is optional.

Offline First

Offline-first is the middle ground. The data lives in the cloud, but the app continues working when you're disconnected. Changes queue up locally and sync when connectivity returns.

This is genuinely useful for certain applications. Field workers who spend time in areas with poor connectivity. Real estate agents viewing properties without reliable Wi-Fi. Airline passengers who want to keep working at 35,000 feet.

I've built an offline-first tool (that didn't find success) for exactly these use cases. A real estate agent tool that works in rural areas. The pattern is well-understood: cache aggressively, queue mutations, sync when possible, resolve conflicts on the server.

The key distinction from local-first is that the server is still authoritative. The offline functionality is a convenience, not a philosophy. When the company shuts down, the offline cache doesn't help you. You still lose your data.

Offline-first also enables async server-side behaviours that local-first precludes. Background jobs. Scheduled tasks. Integrations with external systems. If you need a server to do work on your behalf while you're asleep, offline-first makes more sense than pure local-first.

For most business applications where network connectivity is unreliable, offline-first is the pragmatic choice. You get the UX benefits of working offline without giving up the operational benefits of centralised data.

Cloud Only

Cloud-only is the default model of the modern web. Your data lives on someone else's server. The app requires internet to function. If the company goes under, your data goes with it.

This isn't inherently evil. Cloud enables things that local-first struggles with:

Async behaviours. Scheduled jobs, background processing, integrations with external systems. Things that happen when you're not looking at the app.

Collaboration. Real-time editing, shared workspaces, commenting. Multiple people working on the same data simultaneously with instant updates.

Security of intellectual property. If your business model depends on proprietary algorithms or data processing, you might not want that running on the client.

Subscription economics. Recurring revenue funds ongoing development. One-time purchases fund exactly one version of the app.

The trade-off is dependency. You're trusting the company to stay in business, to not raise prices, to not change the terms of service, to not get acquired by someone who doesn't share your values.

For most SaaS businesses, this trade-off is acceptable. The company has aligned incentives: keep customers happy, stay in business, keep getting paid. The risk of shutdown is real but manageable.

For consumers, the calculus is different. You're betting that a company will exist for as long as you need your data. That's a long time.

The Paprika Problem

Paprika is a recipe management app. It was a one-time purchase. It syncs your recipes across devices via their cloud. It's a good app. I use it.

But here's the thing: Hindsight Labs (the company behind Paprika) has largely stopped developing the app. The one-time purchase means their revenue is front-loaded. The sync infrastructure is an ongoing cost. The math doesn't work forever.

If Hindsight Labs goes under, sync breaks. Not immediately, but eventually. And then you have a local database on each device that can never merge again. Your recipes are stranded.

Paprika is technically local-first, but it misses a crucial element. Portability. The app works offline, but it's still dependent on their proprietary cloud for sync.

Paprika doesn't need a proprietary sync server. It needs a relay. Any relay. The protocol could be open. The data could be yours. The app could outlive the company.

There's zero reason for recipe sync to require a private cloud. But here we are.

When to Use What

Local-first is excellent for:

  • One-time purchase apps where hosting costs matter
  • Tools where data sovereignty is important
  • Personal productivity apps that should last a lifetime
  • Zero-infrastructure hobby projects

Offline-first is excellent for:

  • Field applications with unreliable connectivity
  • Apps that need async server-side processing
  • Business tools where centralised data is operationally important

Cloud-only is excellent for:

  • Collaborative tools with real-time requirements
  • Apps with proprietary processing you want to protect
  • Subscription businesses where ongoing revenue funds development
  • Anything with complex server-side integrations

Conclusion

Local-first is an ethical stance as much as a technical one. It says your data belongs to you. Your software should outlive its creator. You shouldn't be held hostage to someone else's business model.

Evolu makes this practical. CRDTs handle conflicts. End-to-end encryption protects privacy. Stateless relays mean any infrastructure will do. The hard problems are solved.

But for most commercial software, cloud-based still makes sense. It protects intellectual property. It enables async behaviours. It funds ongoing development through subscriptions. The dependency on the company is the point, not the bug.

The future probably isn't one or the other. It's knowing which paradigm fits which problem. Personal tools that should last forever? Local-first. Business applications that need operational control? Cloud. Field tools for unreliable connectivity? Offline-first.

The answer depends on who you're building for, and what promises you're willing to make about how long that software will work.