logo
Kurashizu Blogwhere ideas flow
  • Home
  • News
  • Blog
  • About
  • Home
  • News
  • Blog
  • About

© 2026 Kurashizu. All rights reserved.

Admin·New Post·Service Status
Powered by Cloudflare·30.10.26
← Back to news

Show HN: Durable Actors – OSS Durable Objects with configurable compute

Original article
github.com|19 points|12 comments|by thomask1995|Oct 6, 2026

🚀 Durable Actors: Open-Source Stateful Compute

TerseAI

Durable Actors is a powerful, open-source alternative to Cloudflare Durable Objects. It allows developers to deploy stateful serverless functions without the typical constraints of vendor lock-in, restrictive memory caps, or a lack of visibility.

By providing a foundational layer that handles persistence, coordination, and distributed infrastructure, Durable Actors enable the creation of complex, real-time systems—such as collaborative editors or AI-driven chat bots—with ease.

What is a Durable Actor? It is a class-based entity that combines durable state (data that persists across crashes and restarts) with serialized execution (guaranteeing that messages are processed one at a time to prevent race conditions).


🛠️ Core Architecture & Logic

At its heart, a Durable Actor manages state transitions. Mathematically, we can view the actor's state evolution as: St+1=process(St,message)S_{t+1} = \text{process}(S_t, \text{message})St+1​=process(St​,message) where SSS represents the persisted state and the process is executed sequentially.

Key Capabilities

  • Persistence: Use the @Persisted decorator to ensure data survives interruptions.
  • Concurrency Control: Serialized execution ensures that if multiple users edit a document (like in Notion), the changes are coordinated perfectly.
  • Efficiency: The @Interleave decorator allows the runtime to handle other requests while an actor is awaiting an asynchronous operation (e.g., an LLM API call).

Comparison: Traditional Serverless vs. Durable Actors

FeatureStandard ServerlessDurable Actors
StateStateless (requires external DB)Built-in Durable State\text{Durable State}Durable State
ExecutionParallel/ConcurrentSerialized (per Actor ID)
Lock-inHigh (Provider specific)Low (OSS / Self-hostable)
CoordinationComplex (Distributed Locks)Simple (Single-threaded logic)

🚀 Getting Started

Follow this checklist to spin up your first actor project:

  • Initialize the project
  • Install dependencies
  • Launch the local development server
  • Define your actor logic
  • Generate type-safe clients

1. Installation & Setup

Run the following commands in your terminal:

npx durable-actors init my-actors
cd my-actors
npm install
npx durable-actors dev # Starts the local runtime

2. Defining an Actor

Actors are defined in src/actors.ts. Here is an example of a ChatHistory actor that integrates with an AI SDK:

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[]>) {
    // Send existing history upon connection
    socket.send(this.messages);
  }

  @Interleave 
  async onMessage(_socket: ActorSocket<null, Message[]>, _data: 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);
    // ... handle streaming logic
  }
}

🌐 Integration Flow

Durable Actors use a generated SDK to ensure your backend and frontend remain in sync via type-safe contracts.

Backend Connection

First, generate your client: npx durable-actors generate

Then, create an endpoint to handle WebSocket handshakes:

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.prepareWebsocket({ 
    actorId: "lobby", 
    metadata: null 
  });
  res.json({ websocketUrl: grant.url });
});

Frontend Implementation

Connect your UI using a standard WebSocket:

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>(null);
  const [messages, setMessages] = useState<actors.Outgoing[]>([]);

  useEffect(() => {
    async function connect() {
      const response = await fetch("/api/chat/socket", { method: "POST" });
      const { websocketUrl } = await response.json();
      const ws = new WebSocket(websocketUrl);
      ws.onmessage = (e) => setMessages(prev => [...prev, JSON.parse(e.data)]);
      socket.current = ws;
    }
    connect();
    return () => socket.current?.close();
  }, []);

  const send = (form: FormData) => {
    const text = String(form.get("message"));
    socket.current?.send(JSON.stringify(text));
  };

  return (
    <main>
      <div role="log">
        {messages.map((m, i) => <p key={i}><strong>{m.content}</strong></p>)}
      </div>
      <form action={send}>
        <input name="message" required />
        <button>Send</button>
      </form>
    </main>
  );
}

📈 Observability & Deployment

Durable Actors include built-in tools to monitor your agents in real-time, allowing you to debug state and execution flows without guessing.

o11y-screenshot

Deployment Options:

  1. Local: Use durable-actors dev for rapid iteration.
  2. Cloud: Self-host the runtime on GCP for production workloads.

📚 Further Resources

  • Examples: Explore the AI Chat, Collaborative Documents, and Chatroom samples.
  • Community: Contributions, bug reports, and feature requests are welcome via the contributing guide.
  • License: Distributed under the MIT License.

© 2026 Terse | www.useterse.ai