Isomorphic DSL
Types flow end-to-end. db.select().from(todos).where(eq(todos.done, 0))
means the same thing on the browser and on the Worker, and returns
the same row shape.
plasma is a TypeScript sync engine you drop into a Cloudflare Workers + D1 stack. You define your schema and mutation functions once; they run:
plasma owns the /sync/* endpoints, the change log, the pull cookie,
the outbox, the rebase, the WebSocket poke, the R2 blob uploads for
file() columns, and everything else in between.
Isomorphic DSL
Types flow end-to-end. db.select().from(todos).where(eq(todos.done, 0))
means the same thing on the browser and on the Worker, and returns
the same row shape.
Optimistic + convergent
Mutations apply locally the moment you call them. The sync loop pushes them to the server, rebases on top of concurrent changes, and — with CRDT columns — converges without conflict resolution boilerplate.
Files, encryption, CRDT
Declare a file() column and R2 handles the bytes. Declare
.encrypted() and the client wraps at-rest. Declare
crdtOrSet<string>() and concurrent tabs merge additions and
removals losslessly.
Cloudflare-native
Ships with SyncCoordinator (Durable Object with hibernation-aware
WebSocket fan-out), SequencerDO (per-region monotonic id source),
Miniflare + workerd test harness, and R2 blob storage adapter.
plasma is designed for the shape of app where each user has a manageable set of rows they own or share with a small group: todos, notes, chats, kanbans, drafts, contacts, small collaborative documents.
It is not designed for public feeds (Twitter timeline shape) or analytics-heavy workloads. The change log grows with writes, not with reads, so a heavy-read / light-write app is fine; a shape where a single row is fanned out to thousands of subscribers is not.