Mobile Engineering

Distributed State Management with CRDTs in Flutter

A deep dive into Conflict-free Replicated Data Types (CRDTs) for Flutter developers. Build truly collaborative, offline-capable mobile applications.

Sachin Sharma
Sachin SharmaCreator
Apr 14, 2026
3 min read
Distributed State Management with CRDTs in Flutter
Featured Resource
Quick Overview

A deep dive into Conflict-free Replicated Data Types (CRDTs) for Flutter developers. Build truly collaborative, offline-capable mobile applications.

Distributed State Management with CRDTs in Flutter

In the world of 2026, user expectations for mobile apps have hit a new ceiling. "Offline mode" is no longer a feature; it's a baseline requirement. Users expect to edit their data in a tunnel, on a plane, or in a subway, and have it sync perfectly the moment they reconnect.

Traditional "Last Write Wins" (LWW) strategies are no longer sufficient for collaborative environments. If two users edit the same field offline, LWW simply throws away one person's work. To solve this, we turn to CRDTs (Conflict-free Replicated Data Types).

What is a CRDT?

A CRDT is a data structure that can be replicated across multiple computers in a network, where the replicas can be updated independently and concurrently without coordination between the replicas, and where it is always mathematically possible to resolve inconsistencies.

In simple terms: It's a way to ensure that if Device A and Device B both change data while offline, they will eventually reach the exact same state when they talk to each other, without needing a central server to decide who was "right."

Why Use CRDTs in Flutter?

  1. 2.
    Zero-Latency Interactions: Every change is local first.
  2. 4.
    Scalability: No need for a massive central server to handle conflict resolution.
  3. 6.
    Privacy: Synchronization can happen P2P without data ever hitting a central cloud.

Implementing a Simple Counter CRDT (G-Counter)

The simplest CRDT is a Grow-only Counter.

dart
class GCounter { final Map<String, int> _state; final String deviceId; GCounter(this.deviceId) : _state = {deviceId: 0}; void increment() { _state[deviceId] = (_state[deviceId] ?? 0) + 1; } int get value => _state.values.reduce((a, b) => a + b); void merge(GCounter other) { other._state.forEach((id, count) { _state[id] = max(_state[id] ?? 0, count); }); } }

By storing a count per device and taking the max during a merge, we guarantee that the total value is consistent across all nodes.

Complex Structures: LWW-Map and Sequence CRDTs

For real-world apps (like a collaborative Trello board or a shared note-taking app), we use more complex structures:

  • LWW-Map: For key-value pairs where we want the latest timestamp to win per-field.
  • Sequence CRDTs (like Loro or Yjs): For collaborative text editing where we need to maintain the order of characters inserted by different users.

The Future of Mobile State

As we move towards more decentralized architectures, the logic of "sync" is moving from the server to the client. Flutter is uniquely positioned for this because its efficient Dart runtime can handle the mathematical overhead of CRDT merging without dropped frames.

By adopting CRDTs today, you aren't just building an app; you're building a resilient piece of distributed software.

Sachin Sharma

Sachin Sharma

Software Developer & Mobile Engineer

Building digital experiences at the intersection of design and code. Sharing weekly insights on engineering, productivity, and the future of tech.