State Synchronization
State synchronization keeps multiple representations of related application data consistent while minimizing conflicting sources of truth. For frontend systems, the key challenge is deciding which state is authoritative, which values are derived, and how updates propagate safely.
State synchronization is needed when the same logical information appears in multiple places or is shared across components, browser state, server data, URL state, or persistent storage. The goal is not to duplicate state everywhere, but to define ownership and keep necessary representations consistent.
A robust design starts by identifying the source of truth. For example, a server response may be authoritative for persisted data, while a local store may own transient UI state. Values that can be computed from authoritative state should generally remain derived rather than independently stored, because duplicated writable state can diverge.
Synchronization can be explicit or reactive. A component might dispatch an action that updates a centralized store, while subscribers re-render from the resulting state. In server-driven applications, synchronization may also involve request lifecycles, cache invalidation, optimistic updates, polling, subscriptions, or conflict resolution when remote data changes independently.
Senior-level design focuses on failure modes: stale data, race conditions, lost updates, feedback loops, inconsistent intermediate states, and updates arriving out of order. Solutions often use request identifiers, timestamps or versions, cancellation, transactional updates, idempotent operations, and clearly defined ownership boundaries.
Synchronization should also account for different consistency requirements. A text field's local draft can tolerate temporary divergence from the server, while permissions or financial data may require much stricter guarantees. The appropriate mechanism depends on latency, authority, conflict frequency, and the consequences of stale information.
Key points
- Define one authoritative owner for each piece of mutable state.
- Prefer derived values over duplicated writable state.
- Make update direction and ownership explicit to prevent synchronization loops.
- Handle stale, reordered, duplicated, and failed updates deliberately.
- Choose consistency guarantees based on the data and user experience requirements.
Interview questions
How would you prevent duplicated frontend state from getting out of sync?
First, I would identify which representation is authoritative and remove redundant writable copies where possible. If another representation must exist, I would define an explicit synchronization boundary and update path rather than letting multiple components mutate both copies. Derived values should be computed from the source of truth whenever practical. I would also test transitions where the authoritative value changes independently, because those cases expose stale-copy bugs.
How do you handle race conditions when synchronizing client state with a server?
I would first define which response is allowed to win, rather than assuming the latest response to arrive is the newest data. Depending on the API, that can use request sequence numbers, entity versions, server timestamps, cancellation, or optimistic concurrency controls. The client should reject or reconcile stale responses according to that contract. For mutations, idempotency and server-side conflict handling can be more important than simply ordering requests in the browser.
When should state be synchronized through a global store instead of component state?
I would use component state when the information has a narrow ownership scope and does not need to coordinate unrelated parts of the application. A shared store becomes useful when multiple distant consumers need the same mutable state or when centralized transitions provide meaningful consistency. However, moving everything into a global store can make ownership harder to understand and increase coupling. I would choose the smallest scope that satisfies the coordination requirement.
What is a common source of synchronization bugs in reactive UI code?
A common source is storing a value that can already be calculated from another piece of state. The two values can then change at different times and temporarily disagree. Another common problem is an effect that updates state which triggers the same effect again, producing a loop or unnecessary work. Keeping ownership clear and deriving values when possible reduces these problems.
How would you design synchronization between two browser tabs?
I would establish a shared communication mechanism such as `BroadcastChannel` or another suitable cross-context transport, then define the authoritative data and message semantics. Messages should carry enough information to detect stale or duplicate updates when ordering matters. I would also handle tab startup by obtaining current state rather than assuming every tab has received every historical message. For persistent shared data, the server or durable storage may remain the ultimate authority, with tab-to-tab messaging acting as a propagation optimization.