crdt-kit

Tipos de Datos Replicados Libres de Conflictos para Rust

Ligero (~50KB), compatible con no_std, optimizado para IoT, edge computing, WASM y arquitecturas local-first.

no_std~50KB9 CRDTsDelta SyncWASM0 dependencias
crates.io downloads docs ci
terminal
$ cargo add crdt-kit --features serde

¿Qué son los CRDTs?

Los Conflict-Free Replicated Data Types son estructuras de datos que pueden replicarse en múltiples dispositivos, actualizarse de forma independiente y concurrente, y fusionarse automáticamente sin conflictos.

A diferencia de las bases de datos tradicionales que requieren un servidor central, los CRDTs garantizan que todas las réplicas convergerán al mismo estado sin importar el orden de las actualizaciones.

Esto los hace ideales para apps offline-first, sistemas P2P, redes IoT y cualquier escenario donde los dispositivos necesiten trabajar independientemente.

Tres dispositivos crean datos de forma independiente sin conexión a la red.

TeléfonoAlice
Sin conexión
Notes
Reunión a las 3pm
{A:1, B:0, C:0}
LaptopBob
Sin conexión
Notes
Comprar víveres
{A:0, B:1, C:0}
SensorCarol
Sin conexión
Notes
Deploy v2.1
{A:0, B:0, C:1}

¿Por qué crdt-kit?

Construido para entornos con recursos limitados donde las soluciones existentes agregan demasiado overhead.

~50KB Tamaño binario
0 Dependencias
9 Tipos CRDT
268 Tests
19M ops/seg pico

Funcionalidades

no_std

Corre en bare metal, Raspberry Pi, ESP32. Todos los tipos funcionan con #![no_std] + alloc.

Delta Sync

Solo envía lo que cambió. Trait DeltaCrdt para GCounter, PNCounter, ORSet. Minimiza ancho de banda.

WASM

Bindings wasm-bindgen de primera clase. Mismos CRDTs en navegador, Deno, Node.js y backend Rust.

Migrations

Migraciones transparentes y lazy al leer. Proc macros #[crdt_schema] + #[migration]. Determinístico.

Storage

Tres backends: SQLite (bundled), redb (Rust puro), memoria. Event sourcing, snapshots, compactación.

Codegen

Define entidades en TOML, ejecuta crdt generate. Obtén modelos, migraciones, repositorios, eventos, sync.

Serde

Serialize/Deserialize para los 9 tipos CRDT. JSON, MessagePack, Postcard, CBOR — cualquier formato serde.

Events

Log de eventos completo con append, replay, snapshots, compactación. Trait EventStore en todos los backends.

Dev Tools

CLI: status, inspect, compact, export, generate, dev-ui. Panel web para inspección visual.

Comparación

crdt-kit Automerge Yjs / Yrs
Language Rust Rust JS / Rust
Zero deps (core) 30+ N/A
no_std
WASM Partial Native
Storage SQLite, redb, mem Custom N/A
Migrations Automatic Manual N/A
Delta sync
Event sourcing
Code generation
CLI
Size ~50KB ~500KB+ ~150KB

Inicio Rápido

Cargo.toml
[dependencies]
crdt-kit = "0.3"
main.rs
use crdt_kit::prelude::*;

// Two devices, working offline
let mut phone = GCounter::new("phone");
phone.increment();
phone.increment();

let mut laptop = GCounter::new("laptop");
laptop.increment();

// Reconnect — merge. Always converges.
phone.merge(&laptop);
assert_eq!(phone.value(), 3);

Delta Sync

delta_sync.rs
let mut sensor = GCounter::new("sensor-a");
sensor.increment_by(142);

let mut gateway = GCounter::new("gateway");

// Delta: only send what the gateway doesn't have
let delta = sensor.delta(&gateway);
gateway.apply_delta(&delta);
assert_eq!(gateway.value(), 142);

Schema Migrations

migration.rs
use crdt_migrate::{crdt_schema, migration};

#[crdt_schema(version = 1, table = "sensors")]
struct SensorV1 { device_id: String, temperature: f32 }

#[crdt_schema(version = 2, table = "sensors")]
struct SensorV2 { device_id: String, temperature: f32, humidity: Option<f32> }

#[migration(from = 1, to = 2)]
fn add_humidity(old: SensorV1) -> SensorV2 {
  SensorV2 { device_id: old.device_id, temperature: old.temperature, humidity: None }
}
// v1 records auto-migrate to v2 on load

Arquitectura

Workspace multi-crate. Cada crate versionado independientemente. Usa solo lo que necesites.

1

Definir

Escribe un crdt-schema.toml con entidades, versiones, campos CRDT y relaciones.

2

Generar

Ejecuta crdt generate. Obtén modelos, migraciones, traits de repositorio, eventos, sync.

3

Usar

Importa Persistence<S> en tu app. Accede a repositorios, almacena datos, sincroniza.

Casos de Uso

IoT y Sensores

Core no_std en ESP32, Raspberry Pi. Delta sync por LoRa/BLE. Migraciones manejan OTA.

Apps Móviles

Offline-first. Edita sin red. Los cambios se fusionan automáticamente al reconectar.

Colaboración en Tiempo Real

TextCrdt para edición estilo Google Docs. ORSet para colecciones. Sin coordinador central.

Edge Computing

CRDTs en nodos edge de CDN. Escrituras locales, delta sync. Backend redb puro Rust.

Redes P2P

Sin servidor. Cada peer es igual. Cualquier transporte: WebSocket, WebRTC, Bluetooth.

WASM y Navegador

Misma lógica en backend Rust y navegador. Bindings wasm-bindgen. Un solo codebase.

Demo Interactivo

Dos dispositivos, un chat. Envía mensajes offline, sincroniza — los CRDTs garantizan convergencia.

Two devices chat offline. Messages are unique by ID. On merge, the ORSet unions all messages — none are lost.
Alice's Phone
offline
No messages yet — click send
Bob's Laptop
offline
No messages yet — click send
Alice
Bob

Rendimiento

Medido con Criterion en builds optimizados. 37–700x más rápido que Automerge y Yrs.

vs Automerge y Yrs

Benchmarks comparativos con las dos librerías CRDT más populares del ecosistema Rust.

700× más rápido

Counter ×1000

crdt-kit 33 μs

Automerge 23 ms

37× más rápido

Text insert 1000

crdt-kit 83 μs · Yrs 3.1 ms

Automerge 16.5 ms

62× más rápido

List insert 1000

crdt-kit 265 μs · Yrs 16.5 ms

Automerge 34.4 ms

136× más rápido

Set insert 1000

crdt-kit 203 μs

Automerge 27.6 ms

8M ops/sec

GCounter increment

Incrementar un contador distribuido. La operación más básica y frecuente.

125 μs / 1000 ops

¿Cómo funciona esta prueba?

Se crea un GCounter con un nodo y se llama .increment() 1000 veces consecutivas. Se mide el tiempo total. Un GCounter es un mapa {nodo → cantidad}. Cada increment solo suma 1 a su propio slot — O(1), sin locks.

4.5M merges/sec

GCounter merge

Fusionar 10 réplicas. Simula 10 dispositivos reconectando a la vez.

2.2 μs / 10 replicas

¿Cómo funciona esta prueba?

Se crean 10 GCounters con diferentes nodos, cada uno incrementado varias veces. Se fusionan todos en uno. Merge toma el max() de cada slot. Tiempo lineal respecto al número de nodos.

3.7M ops/sec

Rga insert ×1000

Insertar 1000 elementos en una lista replicada. Para playlists, kanban.

267 μs / 1000 ops

¿Cómo funciona esta prueba?

Rga usa un Vec plano con posicionamiento directo. No hay rebuild de la secuencia — cada insert encuentra su posición en O(n) amortizado. 62× más rápido que Yrs Y.Array, 130× más rápido que Automerge List.

4M ops/sec

TextCrdt insert 1000

Insertar 1000 caracteres en texto colaborativo. Para editores en tiempo real.

246 μs / 1000 chars

¿Cómo funciona esta prueba?

TextCrdt usa Vec plano con len() cacheado en O(1). Cada insert calcula la posición visible y coloca el elemento directamente. 37× más rápido que Yrs Y.Text, 199× más rápido que Automerge Text.

2.8M ops/sec

ORSet insert ×1000

Insertar en un conjunto replicado. Para carritos de compra, listas.

350 μs / 1000 ops

¿Cómo funciona esta prueba?

Cada insert genera un tag único (nodo + reloj lógico). En merge, "add gana" sobre remove concurrente. 136× más rápido que Automerge Map.

7.9M merges/sec

LWWRegister merge

Last-Writer-Wins: el valor más reciente gana. Para perfiles, config, GPS.

12.6 μs / 100 replicas

¿Cómo funciona esta prueba?

LWWRegister guarda un valor + timestamp (Hybrid Logical Clock). Al merge, gana el timestamp más alto. El merge es una simple comparación — O(1) por par.

Medido con Criterion en builds optimizados (release). μs = microsegundos. Comparado con Automerge 0.7 y Yrs 0.25. Haz clic en cada card para detalles.

Garantías Matemáticas

Todos los CRDTs satisfacen Strong Eventual Consistency (SEC). Verificado por 268 tests.

a ⊕ b = b ⊕ a

Conmutatividad

El orden de sync no importa.

(a ⊕ b) ⊕ c = a ⊕ (b ⊕ c)

Asociatividad

Agrupa los syncs como quieras.

a ⊕ a = a

Idempotencia

Seguro de reintentar. Sin duplicados.

CLI para Desarrolladores

status
$ crdt status app.db

Vista general de la base de datos.

inspect
$ crdt inspect app.db sensor-42

Detalle de entidad con event log.

compact
$ crdt compact app.db

Snapshot + truncar event logs.

export
$ crdt export app.db --namespace sensors

Exportar JSON.

generate
$ crdt generate --schema schema.toml

Generar capa de persistencia.

dev-ui
$ crdt dev-ui app.db

Panel web en localhost:4242.

Empieza a construir offline-first

cargo add crdt-kit --features serde