An offline-first application must remain fully functional when the network is absent and reconcile its state with a server once connectivity returns. The single most consequential design decision in such an application is how records are identified. Applications that defer identity assignment to the server, expecting an auto-incrementing primary key, accumulate duplicates, broken references, and irreconcilable merge conflicts the moment a user creates data offline. This article argues that offline-first and local-first applications require stable, client-generated identifiers, and explains the failure modes that stable IDs prevent.
The Problem with Server-Assigned Identity
In a conventional client-server architecture, the client posts a new record without an identifier and the server returns one, commonly an integer from a database sequence. This arrangement assumes the server is reachable at the moment of creation. An offline-first application violates that assumption by design.
Consider a user who creates three notes while disconnected. The local database must store them immediately, which means each note needs an identifier now, not later. If the application invents temporary local integers, two problems follow. First, those integers will almost certainly collide with the server’s eventual assignments and with identifiers generated by the same user on another device. Second, any record that references a note — a tag, an attachment, an edit — must point to it by its temporary ID and then be rewritten when the server reassigns a permanent one. This rewriting is error-prone, and any reference missed during reconciliation becomes a dangling pointer.
The local-first software literature frames this directly: data should belong to the user and remain usable across devices without depending on a central server for basic operation. Identity that originates on the server contradicts that principle, because the most fundamental property of a record — its name — cannot be established offline.
Client-Generated Stable Identifiers
The solution is to generate a globally unique identifier on the client at the moment of creation and to treat it as permanent. A UUID, or a similar collision-resistant value, can be produced locally with no coordination and no network round trip. Because the probability of two independently generated values colliding is negligible, two devices editing the same dataset offline will not assign the same identifier to different records.
A stable identifier is one that never changes for the lifetime of the record. This property is what makes references reliable. A tag that points to a note by its UUID remains valid whether the note was created online or offline, on this device or another, an hour ago or last year. When the device synchronizes, the server stores records under the identifiers the client already assigned rather than minting new ones, so no rewriting is necessary and no reference is invalidated.
In Flutter projects, this typically means generating an identifier in the data layer as part of constructing the model, before the record is persisted to a local store such as SQLite, Drift, or Isar. The identifier is written once and never reassigned. The server’s role shifts from issuing identity to accepting it.
Why Stability Enables Correct Merging
Synchronization is fundamentally a merge operation. Merging requires the ability to ask, for any two records on two devices, whether they represent the same entity. Stable client-generated identifiers answer that question unambiguously: two records are the same if and only if their identifiers match. With this guarantee, a synchronization layer can deterministically detect creations, updates, and deletions, and apply conflict-resolution rules per field rather than guessing at identity.
Without stable identity, merging degrades into heuristics — matching on timestamps, titles, or content — which produce duplicates when they guess wrong and silent data loss when they guess wrong in the other direction. In my experience building offline-first Flutter applications, adopting client-generated UUIDs from the first line of the data model eliminated an entire category of synchronization defects that are otherwise difficult to reproduce and costly to repair.
Conclusion
Identity is the foundation on which an offline-first application is built. Deferring it to the server reintroduces the network dependency that offline-first design exists to remove, and produces duplicates and broken references during reconciliation. Generating stable, globally unique identifiers on the client at creation time allows records and their references to remain valid across devices and sessions, and turns synchronization from a fragile heuristic into a deterministic merge. The identifier should be assigned once, in the data layer, and never changed.