Skip to main content
Meridian is a self-hosted alternative to Liveblocks and PartyKit. Concurrent updates from multiple clients converge automatically using CRDTs — no operational transforms, no conflict resolution code on your end. Sub-millisecond merge latency on a single node. Deltas are broadcast over WebSocket as soon as an op is applied — no polling, no round-trips.

What it is

  • Server: Rust binary. Embedded sled storage by default — PostgreSQL and Redis backends available as optional features.
  • SDK: TypeScript, Effect-based, msgpack wire protocol. Works in Node, Bun, and browsers.
  • Auth: Custom ed25519-signed tokens (smaller than JWT, constant-time verification).
  • Query Engine: Cross-CRDT queries — scan a namespace by glob pattern, filter, and aggregate (sum, union, latest, …) in a single HTTP request.

Quickstart

1. Start the server
MERIDIAN_SIGNING_KEY=$(openssl rand -hex 32) docker compose up -d
2. Install the SDK
bun add meridian-sdk
3. Connect and sync
import { Effect, Schema } from "effect";
import { MeridianClient } from "meridian-sdk";

const client = await Effect.runPromise(
  MeridianClient.create({
    url: "http://localhost:3000",
    namespace: "my-room",
    token: process.env.MERIDIAN_TOKEN!,
  })
);

const views = client.gcounter("gc:views");
views.increment(1);
views.onChange(v => console.log("views:", v));

CRDT types

TypeUse case
GCounterPage views, likes, download counts
PNCounterInventory, vote tallies
ORSetShopping cart, tag sets, collaborative lists
LwwRegisterUser profile, document title, config
PresenceWho’s online, cursor positions, typing indicators
CRDTMapStructured document with independent typed fields
AwarenessEphemeral cursors, selections, “is typing” — not persisted
RGACollaborative text, ordered lists
TreeHierarchical structures, outlines, file trees