cloudflare/agents: Durable Objects as the Runtime for Stateful AI Agents
Build and deploy AI Agents on Cloudflare
At a glance
- What is it?
- Cloudflare's agents package turns Durable Objects into per-user, per-session agent instances with persistent state, callable RPC methods, scheduling, MCP, and workflows. It is a strong fit for Cloudflare-native TypeScript teams and a poor fit for anyone who wants to avoid the Workers platform.
- Who is it for?
- Adopt cloudflare/agents if your stack is already on Workers and you want one agent per user or per session with SQLite-backed state, callable RPC, and hibernation. Do not adopt it if you need a portable runtime or you are unwilling to manage Durable Object bindings and migrations in wrangler.jsonc.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem: agent workloads need a home that remembers
Most agent code starts as a stateless HTTP handler. That works until the agent needs to remember a conversation, hold a WebSocket open, run a task in ten minutes, or resume a stream that a client dropped. At that point you either bolt on Redis and a queue and a scheduler, or you move to a runtime that gives each agent its own addressable identity. cloudflare/agents takes the second path. The README describes agents as "persistent, stateful execution environments for agentic workloads, powered by Cloudflare Durable Objects," and the intended granularity is explicit: "one per user, per session, per game room." That framing tells you who this is for. It is for teams building multi-tenant agent products where isolation between tenants is a structural property rather than something you enforce in application code. A single shared agent process serving thousands of users is the shape this SDK pushes you away from.
The mechanism: a Durable Object subclass with decorators and state sync
The core abstraction is a TypeScript class that extends Agent. In the README's counter example, CounterAgent extends Agent<Env, CounterState>, declares an initialState of { count: 0 }, and exposes two methods marked with the @callable() decorator. Those methods mutate state through this.setState, and the return value goes back to the caller. The state type parameter is not decoration: the React client imports CounterState from the server file and receives it in the onStateUpdate callback, so the state shape is shared across the wire. Routing is handled by routeAgentRequest(request, env), which the default fetch export calls before falling back to a 404. On the client, useAgent from agents/react opens the connection and hands back an object whose stub property lets you call increment() and decrement() as if they were local functions. The README states that "state changes sync to all connected clients automatically." That is the whole loop: a Durable Object holds the state, WebSocket clients subscribe to it, and RPC calls cross the boundary through generated stubs. Everything else in the feature table (scheduling, MCP, workflows, voice, email) is built on top of this same per-object identity.
Getting it running: wrangler.jsonc is where the real work is
Two commands appear in the README. To scaffold, npm create cloudflare@latest -- --template cloudflare/agents-starter. To add the SDK to an existing project, npm install agents. The interesting part is not the install, it is the binding. Because an agent is a Durable Object, the README's counter example requires this in wrangler.jsonc: a durable_objects.bindings entry with name "CounterAgent" and class_name "CounterAgent", plus a migrations array containing { tag: "v1", new_sqlite_classes: ["CounterAgent"] }. The binding name has to match the class the client addresses. The migration tag is how Cloudflare tracks schema changes to the object's SQLite storage, and the README uses new_sqlite_classes rather than new_classes, which ties the agent to SQLite-backed Durable Objects. The example also sets compatibility_date to 2026-06-11 and enables the nodejs_compat flag. If you skip the migration entry, the class will not be instantiable; if you reuse a tag you have already deployed, the deploy will be rejected. This is the step where a first-time user is most likely to get stuck, and the README gives it one short paragraph rather than a walkthrough.
The package split is the first thing that will bite you
The README's packages table lists eight packages, and the truncated note at the end says AI-chat modules used to live under agents/ai-chat-agent, agents/chat, agents/ai-react, and similar subpaths. They now live in @cloudflare/ai-chat and @cloudflare/think. The same pattern applies to voice: @cloudflare/voice is described in the table as a "deprecated compatibility wrapper for the agents/voice exports," which means the maintained path is the agents/voice export inside the core package, not the separately versioned package. The release list reinforces how fast this is moving: agents@0.22.0 shipped on 2026-08-27, alongside @cloudflare/voice@0.4.0 and @cloudflare/voice-twilio@0.0.3. A pre-1.0 core package with a deprecated sibling package and a recently relocated chat module is a normal state for a fast-moving SDK, but it means any tutorial or blog post older than a few months is a liability. Pin your version and read the changelog for the exact release you install.
Where the design pushes back: cold starts, SQLite migrations, and platform lock-in
The README says agents "hibernate when idle and wake on demand" and that each "costs nothing when inactive." That is accurate about billing, but it is not free in latency. A hibernated agent has to be woken before it can answer, and a wake is a Durable Object activation. For a chat agent that is fine. For a synchronous request path with a tight latency budget, it is a cost you have to measure yourself, because the README gives no numbers. The second constraint is storage. Because the agent's state lives in SQLite-backed Durable Objects, schema changes go through the migrations array in wrangler.jsonc. You cannot treat the state shape as a free-form JSON blob that you reshape at will; the migration tag is a deployment artifact with ordering rules. The third constraint is the one the README never states outright: this is not a portable runtime. The Agent base class, routeAgentRequest, the Durable Object binding, the SQLite migration, and the React hooks all assume Cloudflare Workers. If your organization has a policy against single-vendor compute, or you expect to move the agent to another host next year, this SDK is the wrong tool. The code is MIT-licensed, so the licence is not the obstacle; the runtime coupling is.
What you would use instead, and how the approach differs
The obvious alternative is LangGraph, which models an agent as an explicit graph of nodes and edges with a checkpointer for persistence. The difference is where state lives. In LangGraph, the graph definition is your code and the checkpointer is a pluggable backend you choose (in-memory, Postgres, Redis), so the same graph can run on your laptop, in a container, or in a serverless function. In cloudflare/agents, the persistence layer is the execution unit: the Durable Object is the agent, and its identity, storage, and lifecycle are assigned by the platform. That buys you hibernation, per-tenant isolation, and automatic state broadcast to connected clients without writing any of it. It costs you portability and forces you into the Workers deployment model. A second alternative worth naming is plain Workers plus a database, which is what most teams start with. That works until you need scheduling, resumable streams, or a WebSocket that survives a deploy. The agents SDK packages those concerns; if you do not need them, you do not need the SDK.
Maintenance, versioning, and what the MIT licence actually covers
The repository is MIT-licensed and not archived, with the last push dated 2026-09-10. MIT is permissive: you can use, modify, and redistribute the code, including commercially, provided the copyright notice and licence text are retained. That covers the packages in this repository. It does not cover the Cloudflare platform services the packages depend on, which are governed by your Cloudflare account terms and are billed separately. Nothing here is legal advice; if you are embedding the SDK in a product you ship, have counsel read the licence and the platform terms together. On upgrade cost, the release cadence is the signal. agents@0.22.0 is a pre-1.0 version, and the package table already contains one deprecated compatibility wrapper. Expect breaking changes between minor versions and budget time for them. The mitigation is straightforward: pin exact versions in package.json, read the release notes for each bump, and check whether the module you import has moved to a sibling package before you upgrade.
Who this is for, and the one thing to check first
The fit is narrow and clear. You are building a multi-tenant agent product, you are already deploying to Cloudflare Workers, and you want each user or session to have its own stateful, addressable agent with WebSocket sync and scheduling built in. The counter example in the README is the smallest honest demonstration of that: a class, a state type, two callable methods, a binding, a migration, and a React hook. If that shape matches your problem, the SDK removes a lot of infrastructure code. If you are prototyping an agent that will run in a container, or you need to swap model providers and hosting independently, look at a graph-based framework with a pluggable checkpointer instead. The single thing to verify before you commit is the import path for whichever module you need. The README's own note confirms that AI chat moved out of the core package, and the packages table lists a deprecated voice wrapper. Open the version of the docs that matches the version you install, and confirm that the subpath you are importing still exists in that release.
Editorial conclusion
Adopt cloudflare/agents if your stack is already on Workers and you want one agent per user or per session with SQLite-backed state, callable RPC, and hibernation. Do not adopt it if you need a portable runtime or you are unwilling to manage Durable Object bindings and migrations in wrangler.jsonc. Before committing, verify that the agents package version you install matches the documentation at developers.cloudflare.com/agents, since the README notes that AI chat modules moved out of the core package into @cloudflare/ai-chat and @cloudflare/think, and a stale import path is the first thing that will break your build.
Community notes