little-durable-objects
A small, provider-neutral durable-object runtime. Modal is the first sandbox provider; actor state is stored as NDJSON in regional GCS buckets and coordination lives in Postgres.
Install
Install the TypeScript API in actor and workflow projects:
Install the Rust runtime from crates.io:
Container builds can copy the binary from us-central1-docker.pkg.dev/fluid-analogy-473415-c2/public/little-durable-objects:latest. The image is a runtime base, not a complete actor sandbox: actor images also need Node.js, the project code, and little-durable-objects in the project's dependencies.
Quickstart
-
Create a Postgres database and one GCS
STANDARDbucket. Give the service account inGOOGLE_APPLICATION_CREDENTIALSobject access to the bucket. -
Build the Rust runtime and TypeScript package:
-
Start the control plane. Its HTTP origin serves the public REST API and the internal host gRPC API, so it must be reachable from Modal with HTTP/2 enabled.
-
Export actors from
src/durable-objects.tsin your project:import { Actor } from "little-durable-objects" export class Counter extends Actor { count = 0 async increment(): Promise<number> { return ++this.count } } -
From your trusted backend, call the JSON API using
Authorization: Bearer $DURABLE_OBJECT_ADMIN_TOKEN:PUT /v1/namespaces/{namespaceId}/deployment POST /v1/namespaces/{namespaceId}/workflow-tokensThe deployment call atomically ensures the namespace and registers its active deployment. Its body is
{ "codeRevision", "imageRef", "workingDirectory", "actorEntrypoint" }. The workflow-token body is{ "executionId", "deadlineUnixMs", "storageRegion" }.storageRegionselects the home region only when an actor is first created. Later invocations route over gRPC to the actor's existing host region.image_refis a Modal image containing Node.js, your built project, its dependencies, andlittle-durable-objectsat/usr/local/bin/little-durable-objects. -
Give the issued project token to the workflow and call the actor. The package sends an authenticated JSON
POSTto the control plane:import { configureDurableObjects } from "little-durable-objects" import { Counter } from "./durable-objects.js" configureDurableObjects({ token: process.env.DURABLE_OBJECT_TOKEN!, namespaceId: "my-project", controlPlaneUrl: "https://objects.example.com", }) await Counter.get("account-1").increment()
Actors leave memory after 60 seconds idle; empty host sandboxes stop after 5 minutes. Override those defaults with DURABLE_OBJECT_ACTOR_IDLE_TIMEOUT_MS and DURABLE_OBJECT_HOST_IDLE_TIMEOUT_MS on the control plane.
See the architecture diagram for the request, credential, placement, and state flow.
Release maintainers should follow the release guide.
License
MIT © 2026 Terse