Skip to content

Encrypted local-first state, carried by peers

A TypeScript toolkit for encrypted CRDT documents that live on user devices and synchronize without a trusted plaintext database.

Peerborne is a set of composable TypeScript libraries that let you build applications where documents live on user devices and sync directly between peers — encrypted, signed, and content-addressed. There is no application database server. Relays carry ciphertext without seeing plaintext.

A centralized database is simpler and should be the default for most applications. Peerborne is for cases where central custody of plaintext—or dependence on one always-reachable application server—is the downside you need to remove.

Peerborne Note is a small, real Peerborne-and-Automerge application. Create a note locally, choose read-only or editing access, and send one invitation link to a collaborator. Document data is encrypted before it crosses the relay; the relay can still observe connection and traffic metadata and can drop or delay traffic.

Both browsers must remain open and online while the first recipient claims the 15-minute invitation. Peerborne Note is early-stage and not production-ready: do not use it for sensitive or durable data, and do not rely on identity or document recovery, automatic reconnect, revocation UX, or relay failover.

Open Peerborne Note

Read the demo boundaries

Encrypted by default

Stored change payloads, ordinary GossipSub sync envelopes, and load responses are encrypted with the document key (AES-GCM by default). Each complete outgoing ordinary sync message is also signed with ECDSA P-384 by default before encryption. BeeKEM membership-control formats protect their key material with separate recipient- or node-specific encryption. (Ordinary document signing can be configured via enableSigning.)

No trusted plaintext custodian

Helia and libp2p provide local storage and peer-to-peer transport. Relays help peers connect, but carry encrypted document payloads rather than acting as the authoritative application database.

CRDT adapters

Use Yjs or Automerge documents. Replicas converge after valid updates are delivered, without a central consensus service. Battle-tested merge semantics with Peerborne’s security model.

Composable, not monolithic

Six libraries — use only what you need. Core, CRDT adapters (Yjs, Automerge), UI bindings (React, Redux), and client-side indexing.

Once a Peerborne node is configured with the Yjs adapter, documents feel like familiar CRDT shared types wrapped in encryption and access control:

import { Peerborne, SubtleCrypto, defaultConfig,
defaultBootstrapConfig } from '@peerborne/core';
import { YjsProvider, YjsACLProvider,
YjsKeychainProvider, YjsJSONSerializer } from '@peerborne/yjs';
// The application must supply an ECDSA P-384 key pair:
const userKeyPair = await crypto.subtle.generateKey(
{ name: 'ECDSA', namedCurve: 'P-384' },
true,
['sign', 'verify'],
) as CryptoKeyPair;
const swarm = new Peerborne(
userKeyPair.privateKey,
userKeyPair.publicKey,
new YjsProvider(),
new YjsJSONSerializer(),
new YjsJSONSerializer(),
new YjsJSONSerializer(),
new SubtleCrypto(),
new YjsACLProvider(),
new YjsKeychainProvider(),
);
await swarm.initialize(defaultConfig(defaultBootstrapConfig([])));
// Optionally connect to bootstrap peers:
// await swarm.connect(['/dns4/relay.example.com/tcp/443/wss/p2p/12D3...']);
const todos = swarm.doc('/todo-list');
await todos.create();
todos.subscribe('ui', (state) => {
render(state.getArray<string>('items').toArray());
});
await todos.change((state) => {
state.getArray<string>('items').push(['Ship it']);
});

The repository contains runnable examples that show provider setup, identity creation, and connecting peers. See the quick start to run them locally.

Try edits on either in-page replica, disconnect them, and reconnect to merge the queued Yjs updates. The simulation boundary and omitted Peerborne subsystems are listed directly below the demo.

This simulation needs JavaScript and the Web Crypto API. See therunnable repository examples instead.

Initializing simulation…

Illustrative simulation: this runs real Yjs delta/merge via Peerborne’s YjsProvider and uses its SubtleCryptohelper for AES‑GCM encryption and ECDSA P‑384 signatures. It is not protocol-equivalent to Peerborne networking and does not exercisePeerborneDocument, ACL or key onboarding, Helia or a blockstore, libp2p or GossipSub, or any real transport. See therunnable examples for full application setups.

  1. Edit locally. A provider applies each change to the local CRDT replica. The application sees changes immediately — no network round-trip.
  2. Store, sign, encrypt, publish. Peerborne encrypts and stores the change payload under a CID, then signs the complete sync message when enabled, encrypts its serialized envelope, and publishes that full envelope through GossipSub.
  3. Authenticate and merge. Recipients decrypt the envelope, verify its outer signature against known writers when enabled, apply inline history, and fetch only missing or deferred CID payloads. The Yjs or Automerge layer reconciles delivered concurrent edits.

Peerborne currently verifies a signed, distinct-identity invitation and fresh Automerge edits in both directions across a Circuit Relay boundary in CI. Broader partition/rejoin, persistence, public WSS deployment, and relay-failover coverage remains active work.

ChoiceRationale
End-to-end encryptionInfrastructure that lacks the document key carries document-key ciphertext (AES-GCM by default); ECDSA P-384 authenticates sync-envelope signers when enabled.
Content-addressed storageEncrypted serialized change payloads are immutable under their CIDs.
Shadow sync graphEncrypted sync messages carry CID-keyed change trees rather than embedding graph links in stored payloads. Concurrent edits coexist; the CRDT layer resolves delivered changes.
CRDT-agnostic corePeerborne wraps Yjs and Automerge without coupling to either. Swap CRDT implementations without changing your application.
libp2p networkingBattle-tested peer-to-peer stack: WebSockets, WebRTC, WebTransport, Circuit Relay v2, GossipSub.
Q-of-K quorum loadingRequire matching served-frontier hashes from distinct connected peers before binding a selected response. This reduces single-peer risk but does not prove complete interior history.
BeeKEM key sharingDynamic group key encapsulation. Add and remove readers without re-encrypting the document.

See the architecture page for detailed diagrams of the data flow, networking stack, and encryption model.

ToolUse caseServer role
PeerborneEncrypted peer-to-peer CRDT documentsSelf-hosted relay/bootstrap; document payloads end-to-end encrypted
YjsHigh-performance CRDT runtimeBring or configure a sync provider
AutomergeJSON-like CRDT documentsConfigure Repo storage/network adapters
LiveblocksReal-time presence + collaborationManaged backend service
RxDBLocal-first NoSQL databaseFlexible replication to many backends
JazzLocal-first relational databaseManaged or self-hosted sync server
Electric SyncSync Postgres data to clientsPostgres read-path sync engine

Peerborne is designed for end-to-end encrypted documents that sync through self-hosted relay infrastructure without exposing document plaintext. Relays can still observe connection and traffic metadata. See the full comparisons for detailed trade-offs against each project.

Peerborne is young enough that careful bug reports, API feedback, documentation, and unusual network tests can materially shape the project.

Try Peerborne Note

Quick start

Why Peerborne?