Insights30 January 2026Updated 25 October 20265 min read

Offline-First State Management: Redux and MobX for Field Apps

Data continuity offline first architecture tree with devices and cloud icons connected online and offline

A state management library describes how an application changes its working data. It does not, by that description alone, establish that a field record has been saved or accepted by a server. Redux describes state transitions through actions and reducers. MobX's store guidance recommends separating domain stores from the transport used to save their data. We recommend designing those boundaries before choosing between them.

For an offline logging app, start with a specific question: what should the user see after saving an inspection, closing the app and reopening it without a connection? Use that scenario to specify the relationship between the screen, the saved record and the work still waiting to reach the server.

Separate working state from saved records

In Software Architecture in Practice, Bass, Clements and Kazman explain that where state is kept affects recovery after failure. Their discussion concerns distributed services. The design question is useful on a device too: which information must outlive the running process?

For a field app, we would distinguish an unfinished form from a locally saved inspection. We would also distinguish that saved inspection from a server acknowledgement. Specify these as different states, rather than treating a single success banner as evidence of all of them.

Keep temporary interface choices separate where they do not belong in the business record. A selected tab need not have the same storage policy as an inspection result. The Redux FAQ explicitly permits component-local state, while MobX recommends separating domain and interface stores. Neither approach requires every screen detail to become a permanent business fact.

Redux makes transitions explicit

Redux's core model uses a state tree, actions and pure reducers. A reducer takes the previous state and an action, then returns the next state. This gives a team a defined place to inspect what an event means for the application.

In a logging workflow, we would distinguish an edit from a completed local save and a server acknowledgement. Give those events different meanings in the state model. A test can then ask whether the screen says “saved on this device” only after the storage operation has reported success. That is a proposed acceptance rule, not a guarantee supplied by Redux.

For related records, Redux recommends normalised state with items keyed by identifier and relationships expressed through identifiers. In an inspection app, apply that pattern to assets and inspections instead of copying the full asset into every screen's working data.

The practical aim is to make ownership clear when a record changes. Keep editable drafts separate from accepted local records if the workflow needs both. Redux's documentation describes separate current and work-in-progress state, including applying or resetting edits. Decide separately which of those records should survive a restart.

MobX tracks derived information

MobX offers another model. Its computed values derive information from observables and evaluate lazily. While observed, they cache their output and recompute as their dependencies change. By default, unobserved computed values suspend and recompute when accessed. For a field workflow, we would derive a visible count of pending inspections from their recorded status rather than maintain an unrelated counter by hand.

MobX actions delay reactions until the outermost action finishes. That concerns the visibility of in-memory changes to reactions. Do not treat it as evidence that a local database transaction or a server update has completed.

The MobX store guidance recommends one instance of each domain object, with backend communication handled through a separate transport. It permits direct object references, whereas Redux's guidance recommends normalising related data. The common concern is identity: define which local object represents an inspection when an update arrives.

Choose this model if the team can explain and test the observable dependencies. Choose Redux if explicit event-to-state transitions suit the team's review process better. These are selection criteria, not claims that either library is faster or more reliable for every application.

Make synchronisation a separate contract

We recommend recording pending work as part of the offline design, with an explicit rule for when it can be removed. Specify how the app represents a rejected update, an uncertain response and a confirmed acceptance. Keep those meanings independent of the library that renders the screen.

Use a hypothetical inspection to test that contract. Save it locally, interrupt the connection during submission, then restart the app. Ask whether the inspection remains available and whether the interface tells the user what is still unconfirmed. Repeat the scenario with another device changing the same inspection before the first device reconnects.

Decide what the app should do with that competing change before implementing the happy path. For example, require a person to resolve it rather than silently replacing one result. Treat that as a product decision to implement and test, not something reactivity or a reducer can decide on the team's behalf.

Choose against a recovery test

Build a small comparison around the same workflow and the same storage requirements. Ask each implementation to recover an unfinished form and a saved inspection after restart. Then test a rejected synchronisation request and check that the user can distinguish it from an accepted record.

Review the explanation as well as the screen. Can another engineer identify the code that changes the inspection status? Can they find the saved record and the outstanding submission? Can they change the conflict rule without rewriting the interface?

Our recommendation is to choose the approach that makes those answers easiest for the team to prove. Record what “saved” means in the acceptance tests before expanding the app to more field workflows.

Update, October 2026

The distinction between working state and recoverable records also matters in agent systems. Our engineering article on resumption-first memory explains a related design choice: keep the original conversation as the authoritative record and use a summary as an index into it. It offers a separate example of deciding what must survive before choosing how to present it.

Sources

Want this in your team?

Tell us what you're building and where you want to get to, and we'll think it through with you.

Let's have a chat Follow by RSS →

All insights →