Two weeks ago we announced Durable Streams—an open protocol for reliable, resumable streaming to client applications. The response has been fantastic: we're approaching 1,000 GitHub stars, and people are already building with it.
Today we're shipping 0.1.0 releases to npm—the first official packages you can install and use in production. This post covers what's in the release, introduces the State Protocol for database-style sync semantics, and highlights some early experiments from the community.
What's in 0.1.0
npm packages:
npm install @durable-streams/client # TypeScript client
npm install @durable-streams/server # Reference Node.js server
npm install @durable-streams/state # State Protocol primitives
npm install @durable-streams/server-conformance-tests # Server implementation validation
npm install @durable-streams/client-conformance-tests # Client implementation validation
npm install @durable-streams/cli # Development & testing toolsServer implementations:
- Caddy-based server — A production-ready binary built on Caddy for local development and light production workloads. Download from GitHub releases.
Client libraries:
- TypeScript/JavaScript —
@durable-streams/clienton npm - Go —
github.com/durable-streams/durable-streams-go - Python —
pip install durable-streams
Conformance test improvements:
The conformance test suite has grown significantly since launch:
- 124 server conformance tests validating protocol compliance
- 110 client conformance tests—entirely new since the announcement post
The client tests are particularly important. We've ported a substantial portion of the test suite from @electric-sql/client, which has been battle-tested over 18 months of production use in Electric. These tests cover:
- Offset semantics: monotonic offsets, byte-exact resumption without skips or duplicates, offset persistence across sessions
- Retry behavior: automatic retry on transient errors (500, 503, 429), respecting Retry-After headers, not retrying permanent errors (4xx)
- Live streaming: SSE and long-poll modes, receiving both existing and new data, proper timeout handling, up-to-date signals
- Streaming equivalence: verifying SSE and long-poll produce identical results for the same stream and offset
- Message ordering: strict order preservation across all read modes (catchup, long-poll, SSE)
- Producer operations: stream creation, data appending, batching, sequence ordering
Early feedback from implementers has been invaluable in tightening up the spec and removing ambiguity. Thanks to everyone who's been testing their implementations and reporting edge cases—this kind of community input makes the protocol stronger for everyone.
If you're building your own implementation, both test suites are available as @durable-streams/server-conformance-tests and @durable-streams/client-conformance-tests. Run them against your server or client to validate compatibility before shipping.
The conformance test suite validates that all implementations behave identically—same protocol, same semantics, your choice of language.
Try It Out Now
The fastest way to see Durable Streams in action is with the server binary and curl.
1. Download and run the server:
Download the latest server binary for your platform from the releases page.
Available builds: macOS (Intel & ARM), Linux (AMD64 & ARM64), Windows (AMD64).
Extract the archive and run:
./durable-streams-server devThe server starts on http://localhost:4437.
2. Create a stream:
curl -X PUT http://localhost:4437/v1/stream/my-first-stream \
-H 'Content-Type: text/plain'3. Append some data:
curl -X POST http://localhost:4437/v1/stream/my-first-stream \
-H 'Content-Type: text/plain' \
-d 'Hello, Durable Streams!'The response includes an X-Offset header—that's your position in the stream.
4. Read the stream:
curl http://localhost:4437/v1/stream/my-first-stream5. Watch it live:
Open a terminal and start tailing with SSE:
curl -N http://localhost:4437/v1/stream/my-first-stream?offset=-1&live=sseIn another terminal, append more data:
curl -X POST http://localhost:4437/v1/stream/my-first-stream \
-H 'Content-Type: text/plain' \
-d 'This appears in real-time!'Watch it appear instantly in your first terminal. That's durable streaming—ordered, resumable, and live.
Introducing the State Protocol
In the announcement post, we described a composable ecosystem with Durable Streams as the foundation and higher-level protocols built on top. The State Protocol is the first of those higher-level protocols.
Like Durable Streams itself, the State Protocol is extracted from Electric's Postgres sync protocol—refined over 18 months of production use and now standardized as a standalone protocol that works over any durable stream.
Durable Streams gives you ordered, resumable byte delivery. The State Protocol adds semantic meaning: insert, update, and delete operations on typed entities. It's the vocabulary you need for database-style sync—presence tracking, chat rooms, feature flags, collaborative state—without prescribing how you store or query that state.
The Shape of a Change Event
{
type: "user", // Entity type (routes to collection)
key: "user:123", // Unique identifier
value: { // The entity data
name: "Alice",
email: "alice@example.com"
},
headers: {
operation: "insert", // insert | update | delete
txid: "abc-123", // Optional transaction ID
timestamp: "2025-12-23T10:30:00Z"
}
}Why Separate Protocols?
Separation means you can adopt what you need:
- AI token streaming? Use Durable Streams directly—you don't need insert/update/delete semantics for tokens.
- Real-time database sync? Add the State Protocol for typed collections with proper CRUD operations.
- Both in the same app? Different streams can use different protocols.
Using the State Protocol
For basic use cases, MaterializedState gives you an in-memory key-value store that applies change events:
import { MaterializedState } from "@durable-streams/state"
const state = new MaterializedState()
state.apply({
type: "user",
key: "1",
value: { name: "Kyle" },
headers: { operation: "insert" }
})
const user = state.get("user", "1") // { name: "Kyle" }For applications that need reactive queries, filtering, joins, and optimistic updates, @durable-streams/state integrates with TanStack DB:
import { createStateSchema, createStreamDB } from "@durable-streams/state"
import { useLiveQuery } from "@tanstack/react-db"
import { eq } from "@tanstack/db"
const schema = createStateSchema({
users: {
schema: userSchema, // Define your schema
type: "user",
primaryKey: "id"
}
})
const db = createStreamDB({
streamOptions: { url: streamUrl, contentType: "application/json" },
state: schema
})
// Reactive query that updates automatically
const activeUsers = useLiveQuery((q) =>
q.from({ users: db.collections.users })
.where(({ users }) => eq(users.active, true))
)TanStack DB uses differential dataflow under the hood, so queries recompute incrementally when data changes, which is dramatically faster than filtering in JavaScript.
The full State Protocol specification is available at STATE-PROTOCOL.md.
Community Experiments
The best part of launching has been seeing what people build. Here's what the community has been exploring:
AI Agents and Workflows
The agent use case has resonated strongly. Nathan Flurry built an experimental integration combining Durable Streams with Rivet Actors—actors as "the brains & memory" and Durable Streams as "the pipes":
Kames has been building agent workflows with Mastra on top of Durable Streams:
And the conceptual simplicity is clicking for people:
Resilient Streaming Demos
Sam Willis demonstrated multimodal GenAI streaming (text + audio) with reconnection—lose the connection, reconnect, and keep listening from exactly where you left off while the model keeps generating:
Kyle built demos showing Durable Streams handling the Wikipedia events firehose with TanStack DB and real-time state sync:
Integration Proposals
The LiveStore team opened an issue proposing a sync provider to integrate Durable Streams with their SQLite-powered local-first framework. The discussion explores how the two projects' shared philosophy—append-only event logs, offset-based resumption, local-first architecture—could combine to give users CDN-friendly sync with structured event schemas and reactive UI bindings.
The Protocol Advantage
People are noting the value of standardization over vendor lock-in:
Even the TanStack team is excited about the HTTP-native approach:
And Nathan Flurry's making bold predictions:
New Implementations
The protocol is already attracting new implementations. Ahimsa Labs released a Go client, and Evil Martians announced they're gradually adopting Durable Streams in AnyCable—starting with implementing the read part of the protocol for consuming durable streams. Their post "AnyCable, Rails, and the pitfalls of LLM-streaming" explores the exact reliability challenges Durable Streams solves.
Valter Balegas built a Yjs provider for Durable Streams—bringing real-time collaborative editing with conflict-free sync semantics to the protocol. The provider includes awareness/presence support and a demo application showcasing collaborative text editing with colored cursors.
What's Next
- Hosted cloud version: We're building our own cloud implementation of Durable Streams, launching in January 2026.
- More language implementations: The protocol is designed to have many implementations. We'd love to see servers and clients in Rust, Java, Swift, and more.
- Database adapters: Postgres, MySQL, and SQLite adapters using the State Protocol—streaming database changes to clients with proper sync semantics.
- Electric 2.0: This is all foundational work for the next version of Electric.
Get Started
Install the packages:
npm install @durable-streams/client @durable-streams/stateOr use your language of choice:
go get github.com/durable-streams/durable-streams-go
pip install durable-streamsIf you're building a server implementation, the conformance test suite will validate compatibility.
Join us in Discord to share what you're building.


