Today for AI

Hacker News AI · 10/6/2026, 3:58:19 PM

Durable Actors: OSS Alternative to Cloudflare Durable Objects

68AI Score
Executive Summary

Durable Actors launches as an open-source alternative to Cloudflare Durable Objects, offering configurable compute and no vendor lock-in. By defining Actors with durable state and serialized execution, it simplifies building distributed apps like chat systems and agent swarms, featuring built-in memory limits and observability.

SOURCE COVERAGEOriginal coverage

Contents9 sections

an open-source alternative to Cloudflare Durable Objects... with no vendor lock-in, memory limits, and observability built in.

Durable Actors help you build real-time applications like chat systems (e.g. ChatGPT, Codex), collaboration tools (e.g. Notion), and agent swarms (e.g. Devin).

They provide stateful serverless functions, a foundational building block that abstracts away persistence, coordination, and infrastructure challenges in distributed systems.

Live demo · TypeScript documentation · Python documentation

How it works

  1. Define an actor, a class with durable state (i.e. data survives interruptions, errors, and restarts) and serialized execution (i.e. concurrent callers can update it safely). For example:
  • If you were building ChatGPT... a chat actor can store conversations that survive LLM flakiness and server crashes (durable state)
  • If you were building Notion... a document actor can coordinate concurrent edits from several people and agents (serialized execution)
  1. Generate type-safe clients automatically with the Durable Actors SDK. For now, it supports Python and TypeScript.
  2. Develop locally with one command and later self-host the Durable Actors runtime on GCP.

Quickstart: Multiplayer AI Chat

Teammates share one TeamAgent chat across regions; prompts queue, replies stream to everyone, and conversation state is durably persisted.

1. Create your project

Install Node.js 22.19+ and Bun 1.3.9+.

SH
npx durable-actors init my-actors
cd my-actors
npm install
npx durable-actors dev # Run the server locally on your machine

2. Define an actor

Define and export actors in your actor project’s src/actors.ts, the default entrypoint loaded by durable-actors dev. The runtime loads actors on demand and persists fields marked @Persisted.

For example, a chat history actor:

TS
import { openai } from "@ai-sdk/openai"
import { streamText } from "ai"
import { Actor, type ActorSocket, Interleave, Persisted } from "durable-actors"

type Message = { role: "user" | "assistant"; content: string }

export class ChatHistory extends Actor<null, string, Message[]> {
    @Persisted messages: Message[] = []

async onConnect(socket: ActorSocket<null, Message[]>) {
        socket.send(this.messages)
    }

@Interleave // Let other calls run during await, e.g. new connections while a reply streams.
    async onMessage(_socket: ActorSocket<null, Message[]>, text: string) {
        this.messages.push({ role: "user", content: text })
        const result = streamText({ model: openai("gpt-5-mini"), messages: [...this.messages] })
        const reply: Message = { role: "assistant", content: "" }
        this.messages.push(reply)
        this.broadcast(this.messages)
        for await (const chunk of result.textStream) {
            reply.content += chunk
            this.broadcast(this.messages)
        }
    }
}

3. Connect your backend

We make it super easy to integrate the actors into your existing tech stack. Just generate the client and you get a fully type safe contract to interact with.

SH
npx durable-actors generate

Create a WebSocket connection to one shared chat:

TS
import express from "express"

import { actors } from "../generated/index.js"

export const app = express()

app.post("/api/chat/socket", async (_req, res) => {
    const grant = await actors.ChatHistory.prepareWebsocket({
        actorId: "lobby",
        metadata: null
    })
    res.set("Cache-Control", "no-store").json(grant)
})

4. Connect the frontend

TSX
import { useEffect, useRef, useState } from "react"
import { createRoot } from "react-dom/client"

import type { actors } from "../generated/index.js"

function Chat() {
    const socket = useRef<WebSocket>(null)
    const [messages, setMessages] = useState<actors.ChatHistory.Outgoing>([])

useEffect(() => {
        let active = true
        async function connect() {
            const response = await fetch("/api/chat/socket", { method: "POST" })
            const { websocketUrl } = await response.json()
            if (!active) return
            socket.current = new WebSocket(websocketUrl)
            socket.current.onmessage = event => setMessages(JSON.parse(event.data))
        }
        void connect()
        return () => {
            active = false
            socket.current?.close()
        }
    }, [])

function send(form: FormData) {
        const text = String(form.get("message")).trim()
        if (!text || socket.current?.readyState !== WebSocket.OPEN) return
        socket.current.send(JSON.stringify(text))
    }

return (
        <main>
            <div role="log" aria-label="Messages">
                {messages.map((message, index) => (
                    <p key={index}><strong>{message.role}:</strong> {message.content}</p>
                ))}
            </div>
            <form action={send}>
                <input name="message" aria-label="Message" required />
                <button>Send</button>
            </form>
        </main>
    )
}

createRoot(document.getElementById("root")!).render(<Chat />)

For a complete app with error handling and retries, see the AI Chat example.

5. Monitor and debug

Durable Agents provides built-in observability features:

o11y-screenshot

Examples

For complete sample applications, see AI Chat, Collaborative Documents, and Chatroom.

Community

Bug reports, feature requests, documentation fixes, and code contributions are welcome. See the contributing guide for repository setup and checks, and follow our code of conduct.

Use GitHub Issues for bugs, ideas, and questions. Report vulnerabilities privately using our security policy.

Follow development and release notes on GitHub Releases.


作者发帖说明(HN):

Hi HN, we're Thomas and Olivier from Terse (https://www.useterse.ai/) We've built Durable Actors, an open-source alternative to Cloudflare's Durable Objects.

A Durable Object/Actor is a tiny server that handles one request at a time and has its own SQLite database. There's exactly one of each in the world and it is addressed by name.

This is the perfect primitive for deploying multiplayer agents. Each agent can have its own Durable Actor, and each user can connect to that Actor via websocket. This is fully horizontally scalable. Your users can deploy and share agents at will without putting pressure on a central DB or websocket server.

Durable Actors are also great for coordinating agents within a system. Since only one request is handled at a time, you can protect critical data such as a CRM and allow multiple agents to run concurrently without worrying about data races.

The only alternative to this is Cloudflare's Durable Objects. However, there is extreme lock in (they pull you into D1, R2 + workers as well) and it wasn't originally built for agentic workfloads when it was released 5 years ago.

Some notable projects built on Durable Objects include RampInspect, OpenInspect as well as the multiplayer frameworks Liveblocks and PartyKit. You can now build these kinds of projects on Durable Actors.

Durable Actors is a version of DO that is built for concurrent agentic workloads. It is fully open source (MIT License) and includes a helm chart f...