Technical9 min read

What is offline-first architecture and why does your app need it?

Your app shouldn't stop working because the user entered the subway. I explain how to implement offline-first with event sourcing — the architecture I use in my 6 apps.

Facundo Campo·

30% of the time a user uses a mobile app, the internet connection is poor or nonexistent. On the subway, on a plane, in rural areas, or simply with weak signal. If your app depends on internet to function, you're losing 30% of your engagement. Offline-first means the app works fully without internet and syncs when connection returns. It's the difference between a professional app and an amateur one.

How it works: Event Sourcing

Instead of sending every action to the server in real-time, the app records each action as an immutable "event" with a unique UUID. These events are stored locally in a queue (AsyncStorage). When there's internet, the queue is sent to the server in batches. The server processes events in order and returns the updated state. If an event was already processed (same UUID), the server ignores it. This guarantees idempotency: no matter how many times you send the same event, the result is the same.

State lives in memory

During active gameplay, the complete state lives in RAM (Zustand store). Zero disk or network operations. This guarantees constant 60 FPS. Autosave happens with debounce every 10 seconds using InteractionManager.runAfterInteractions() to avoid blocking the UI. When the user closes the app, state is persisted to AsyncStorage. When they reopen, it rehydrates from there.

Smart sync

It's not always a good idea to sync. My implementation evaluates: whether there's WiFi or mobile data, battery level (no sync in power save mode), number of pending events, and time since last sync (minimum 30 seconds between syncs). If sync fails, it retries with exponential backoff: 5 seconds, 15 seconds, 60 seconds. After 3 failed attempts, it waits until the user reopens the app.

Conflict resolution

The server always wins. When the server receives events, it processes them in chronological order and calculates the final state. That state is sent back to the client, which replaces its local state. This works because events are immutable and have timestamp + UUID. Even if the user played on two devices without connection, when both sync, the server reconciles events chronologically and the result is consistent.

Anti-cheat with Event Sourcing

An unexpected benefit: since every action is a recorded event, the server can analyze patterns. If a user completes a difficult Sudoku in 5 seconds, the events show they only made 3 moves — clearly impossible. The server calculates a "suspicion score" and can apply shadow bans without the cheater knowing. All this logic is server-side and can't be bypassed by manipulating the client.

Your project

Want an app that works perfectly without internet? I can build it with this architecture. Check my published apps and contact me for your project.

#offline first architecture#event sourcing mobile app#offline first react native#mobile app sync#offline app design