A TypeScript playground for exploring Local-First systems and offline consistency.
This repository is a reference implementation of Conflict-free Replicated Data Types (CRDTs).
CRDTs are data structures that allow multiple replicas to update state independently and still converge to the same result after merging, without coordination or a central authority.
The goal of this project is to understand those guarantees by implementing common CRDTs from scratch, focusing on merge logic, correctness, and testability. Networking, storage, and transport layers are intentionally out of scope.
✨ AI-Assisted, Human-Directed. AI helped polish the docs, structure, and code, but every single line was personally reviewed and steered by Shubham Mathur
These are the CRDTs you actually need to understand to grok most local-first systems.
| The CRDT | What it does | Real-World Example |
|---|---|---|
| G-Counter | A number that only goes up | View counts, metrics |
| PN-Counter | A number that goes up and down | Inventory, scores |
| G-Set | A set you can add to, but never delete from | Audit logs, append-only histories |
| LWW-Set | A set where the last write wins | User settings, simple sync state |
All of these follow standard state-based CRDT merge semantics and guarantee convergence under concurrent updates.
Nothing fancy here. Logic lives in src, docs live in docs, and tests sit close to the code so you don’t have to hunt for them.
├── src/
│ ├── crdts/ # The math & merge logic
│ ├── interfaces/ # Shared CRDT contracts
│ └── index.ts # Public entry point
├── docs/ # Conceptual deep dives
├── package.json
└── tsconfig.json
If you want to poke at it locally:
git clone https://github.com/googleknight/crdt-lib.git
cd crdt-lib
npm install
npm run demoHere’s a simple example showing how conflicts disappear without coordination.
import { LWWSet } from "./src";
const nodeA = new LWWSet("node-a");
const nodeB = new LWWSet("node-b");
// Everyone goes offline
nodeA.add("Milk");
nodeB.add("Eggs");
nodeB.add("Milk");
nodeB.remove("Milk"); // Changed their mind
// Everyone comes back online
nodeA.merge(nodeB);
// Deterministic result
console.log(nodeA.value); // ["Eggs"]No locks. No leader. No drama.
CRDTs are easy to write and surprisingly easy to get subtly wrong.
A couple of unit tests won’t cut it.
This repo uses a three-layer testing strategy to keep things honest.
| Command | Test Type | What it answers |
|---|---|---|
npm run test:unit |
Unit tests | “Does the math work?” |
npm run test:int |
Integration | “Can replicas actually merge?” |
npm run test:sim |
Simulation | “Does everything still converge under chaos?” |
The simulation tests throw large numbers of randomized operations at multiple replicas in random orders. If they don’t all end up with the same final state, the test fails.
Found a bug? Want to add something spicy like a Sequence CRDT?
- Fork the repo
- Create a branch
- Add code and tests
- Open a PR
Built and maintained by Shubham Mathur
Happy syncing 🚀