HomeReadTactics deskA Kotlin CRDT Playbook for Offline-First Apps Without a Sync Server
Tactics·Jul 4, 2026

A Kotlin CRDT Playbook for Offline-First Apps Without a Sync Server

A technical post details an architecture using Conflict-Free Replicated Data Types in Kotlin Multiplatform to eliminate complex sync backends, trading them for simple blob storage and smarter…

A technical post details an architecture using Conflict-Free Replicated Data Types in Kotlin Multiplatform to eliminate complex sync backends, trading them for simple blob storage and smarter clients.

A technical tutorial posted by "software_mvp-factory" on dev.to outlines a specific playbook for building offline-first applications without a complex, stateful synchronization server. The core of the argument is architectural: by embedding conflict resolution logic directly into the client using Conflict-Free Replicated Data Types (CRDTs), a development team can replace a custom backend with commodity object storage. This approach is presented as a way to reduce server maintenance, eliminate a single point of failure, and accelerate development for cross-platform mobile apps.

The strategy targets a common failure mode in mobile development. Teams often build a centralized server to act as the final arbiter for conflicting data writes from different clients. The author argues this leads to an ever-growing surface area of fragile, edge-case logic that is difficult to maintain. The proposed alternative uses CRDTs, data structures that are mathematically guaranteed to converge to the same state across all clients, provided they all receive the same set of updates. The order of updates does not matter.

Replace the server with primitives

The playbook's central move is to shift logic from the server to the client. Instead of a smart server managing dumb clients, smart clients can sync their state through a simple, stateless storage layer like Amazon S3 or Google Cloud Storage. The author provides a table of CRDT primitives suited for different tasks, recommending that most mobile application needs can be met with just two: Last-Write-Wins Registers (LWW-Register) and Observed-Remove Sets (OR-Set).

LWW-Registers are suitable for simple values like user profile fields or settings, where the value with the newest timestamp always wins. OR-Sets handle collections like tags or favorites, where items can be added and removed without complex coordination. The post explicitly notes that more complex primitives, like the Replicable Growable Array (RGA) for collaborative text, are only necessary for ordered sequences and introduce higher overhead.

One implementation for iOS and Android

The capital efficiency of the model relies on Kotlin Multiplatform (KMP). The core CRDT logic is written once in a commonMain module and compiled for both iOS and Android. This avoids duplicating complex synchronization code and ensures identical behavior across platforms. The author provides a concrete implementation of an LWWRegister data class in Kotlin to demonstrate this principle.

data class LWWRegister<T>(
    val value: T,
    val timestamp: Long,
    val nodeId: String
) {
    fun merge(other: LWWRegister<T>): LWWRegister<T> = when {
        other.timestamp > this.timestamp -> other
        other.timestamp < this.timestamp -> this
        other.nodeId > this.nodeId -> other // Tie-break with node ID
        else -> this
    }
}

This code, residing in the shared module, handles the merge logic. The client application becomes responsible for fetching the latest state from blob storage, merging it with local changes, and writing the new state back.

What We'd Change

The playbook presents a clean architectural pattern, but its simplicity in a tutorial context obscures real-world operational costs. The promise to "kill your sync server" is an overstatement. The server is not eliminated; its role shifts from a complex logic arbiter to a simpler infrastructure component. That component still requires engineering.

First, blob storage is not a complete backend. A production system still needs services for authentication, authorization, and potentially rate limiting to prevent abuse. These are not trivial to implement correctly. Second, clients need a way to be notified of updates. Without a server managing connections, this typically falls to platform-specific push notification services, adding another piece of infrastructure to manage.

Finally, the CRDT model itself has limitations. The post acknowledges that some primitives create "tombstones" for deleted data, which accumulate over time and can bloat the dataset. This is a significant long-term concern for applications with high churn in collaborative content. The model is also less suitable for data that requires immediate, authoritative server-side validation, such as claiming a unique username or processing a financial transaction. The playbook is powerful, but its boundaries are sharply defined by the application's data model.

Landing

This architecture represents a deliberate trade-off. It exchanges the cost of developing and maintaining a stateful, logic-heavy backend for increased client-side complexity and a dependency on stateless cloud primitives. For solo founders or small teams building productivity or content-focused apps, this can be a winning trade. It allows them to deliver a robust offline-first user experience, a key competitive differentiator, with significantly less backend overhead. The approach is not a universal solution, but a specialized tool for a specific class of capital-efficient product development.

The investor read

This playbook signals a capital-efficient path to building offline-first applications, a feature that can be a key moat in user-centric SaaS. By offloading complex sync logic to the client and using commodity blob storage, a solo developer or small team can compete on user experience without the high fixed costs of building and maintaining a stateful backend. This is a classic bootstrapped or lean-VC maneuver. It's most investable for products where the core value is in the client-side experience and the data model is compatible (e.g., note-taking apps, personal CRMs, design tools). It is a red flag for businesses requiring heavy server-side transactional integrity, real-time analytics, or complex permission models that cannot be implemented on the client. The pattern indicates a broader trend toward more powerful clients and dumber, more commoditized backends.

Pull quote: “The server is not eliminated; its role shifts from a complex logic arbiter to a simpler infrastructure component.”

Sources · how we verified
  1. CRDTs in Kotlin Multiplatform: Kill Your Sync Server

Every claim ties to a primary source. See our methodology.

Reported by the Maya desk on Founderr Pulse’s Tactics beat. Every factual claim is tied to a primary source and linked; anything that can’t be stood up doesn’t run. Founderr (RIKHATH LLC) is the accountable publisher and corrects in place. How we work · About · File a correction.
M
Maya

The Maya desk covers tactics: concrete playbooks, growth experiments, and operating decisions indie founders are running now. Every claim is sourced and linked. Operated by Founderr (RIKHATH LLC) See the desk →

Founderr Pulse — free & independent. The desk for people who build & back.