cloudflare/agents: persistent stateful agents on Durable Objects
Build and deploy AI Agents on Cloudflare
At a glance
- What is it?
- The agents SDK gives each AI agent its own Durable Object with state, storage and lifecycle. It is a strong fit if you already deploy Workers; it is the wrong tool if you need long CPU-bound jobs.
- Who is it for?
- Adopt cloudflare/agents if your team already ships Cloudflare Workers and you want per-user or per-session agent state without running your own session store. Do not adopt it if you need long CPU-bound jobs, since the README describes agents that hibernate when idle and wake on demand, which is a request-driven model rather than a batch compute service.
- 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 received new commits within the last day.
- 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 29, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem cloudflare/agents solves: state that outlives a request
A stateless HTTP handler forgets everything between requests. Any agent that needs memory of a conversation, a per-user counter, or a scheduled follow-up has to push that state somewhere else: Redis, a database, a queue. The README frames the SDK as an answer to that. Agents are described as "persistent, stateful execution environments for agentic workloads, powered by Cloudflare Durable Objects", where each agent gets "its own state, storage, and lifecycle".
The intended audience is narrow and specific. You are a TypeScript developer who already deploys to Cloudflare Workers, and you want one agent instance per user, per session, or per game room. The README says you can run millions of them and that "each costs nothing when inactive", because agents hibernate when idle and wake on demand. That cost model is the actual selling point. A long-lived process per user would be expensive; a Durable Object that sleeps between messages is not.
If you are not on Workers, this is a poor starting point. The SDK is not a portable agent framework that you can host anywhere. Routing, state persistence, scheduling and hibernation all assume the Durable Objects runtime.
How an agent maps onto a Durable Object
The mechanism is visible in the quick example. You subclass Agent with two type parameters, the environment and the state shape, and give it an initialState. Methods decorated with @callable() become RPC endpoints. Calling this.setState() inside one persists the new value and, per the README, "state changes sync to all connected clients automatically". The client does not poll. It opens a WebSocket through useAgent and receives the update.
The agent is a Durable Object, and that has a concrete consequence: it needs a binding and a SQLite migration in wrangler.jsonc. The README shows both under durable_objects.bindings and migrations with new_sqlite_classes. Miss the migration and the class will not exist at runtime. This is the part people skip when they skim the example.
Around that core, the repository is a monorepo with far more than the core SDK. The packages table lists @cloudflare/ai-chat for persistent messages and resumable streaming, @cloudflare/codemode for LLMs that write executable TypeScript instead of issuing one tool call at a time, @cloudflare/shell for sandboxed JS execution with a virtual filesystem, hono-agents as middleware, and @cloudflare/voice, which the README itself labels a "Deprecated compatibility wrapper" for the agents/voice exports. That deprecation note is worth reading before you build a voice feature on the wrapper package.
Installing cloudflare/agents and running a first agent
The README gives two entry points. For a new project, scaffold the starter template:
npm create cloudflare@latest -- --template cloudflare/agents-starterFor an existing project, install the package:
npm install agentsThe starter template is the faster path because it already contains the Wrangler configuration described below. If you add the package to an existing Worker, you write that configuration yourself.
A minimal agent subclasses Agent, declares initialState, and exposes methods through the @callable() decorator. The README's counter example looks like this:
import { Agent, routeAgentRequest, callable } from "agents";
export type CounterState = { count: number };
export class CounterAgent extends Agent<Env, CounterState> {
initialState = { count: 0 };
@callable()
increment() {
this.setState({ count: this.state.count + 1 });
return this.state.count;
}
}Routing is a single call in your fetch handler. routeAgentRequest returns a Response when the request matches an agent route, and null otherwise, so the nullish coalescing pattern from the README falls through to your own 404:
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
return (
(await routeAgentRequest(request, env)) ??
new Response("Not found", { status: 404 })
);
}
};The binding and migration are required, not optional. The README's wrangler.jsonc shows a Durable Object binding named after the class and a migration tagged v1:
{
"name": "counter",
"main": "server.ts",
"compatibility_date": "2026-06-11",
"compatibility_flags": ["nodejs_compat"],
"durable_objects": {
"bindings": [{ "name": "CounterAgent", "class_name": "CounterAgent" }]
},
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["CounterAgent"] }]
}On the client, useAgent opens the connection and onStateUpdate pushes new state into React. Calling agent.stub.increment() invokes the remote method; the returned value is the new count. What you should see is the count changing in every open tab at once, because the state sync is broadcast rather than pulled.
Where cloudflare/agents stops being the right choice
The hibernation model is a constraint, not just a cost feature. An agent that sleeps when idle is not a place to run a forty-minute CPU-bound computation. The README describes a lifecycle built around wake on demand, and the Workflows feature is described as "durable multi-step tasks with human-in-the-loop approval", which implies steps that pause and resume rather than one long blocking call. If your workload is a batch job, a video transcode, or anything that must hold a process open, the Durable Objects execution model will fight you.
The second limitation is lock-in depth. State, storage, scheduling, WebSockets, MCP transport and the client hooks all assume the Cloudflare runtime. There is no documented adapter for running the same agent class on Node or another host. The browser package, agents/browser, moves agents into a browser tab, which is a different deployment target, not a portability story.
Third, the surface area is large and still moving. The repository ships core agents, ai-chat, think, codemode, shell, worker-bundler and hono-agents as separate packages, plus a deprecated voice wrapper. The README notes that AI-chat modules "used to live in agents/ai-chat-agent, agents/chat, agents/ai-react, and agents/ai-t...", meaning import paths have already moved once. Pin your versions and read the changeset for each release rather than tracking main.
How cloudflare/agents differs from a framework like LangGraph
The honest comparison is with graph-based orchestration frameworks. Those treat the agent as a computation you define: nodes, edges, a state machine, and a runtime you host yourself. cloudflare/agents treats the agent as a deployed object with an address. The unit of deployment is one Durable Object instance per user or session, and the framework's job is routing, persistence and hibernation rather than graph execution.
The practical difference shows up in two places. First, persistence: in a graph framework you wire up your own checkpointer and database; here setState and the SQLite-backed Durable Object storage are part of the primitive. Second, transport: real-time sync to connected clients is built in, so a React frontend gets updates without a separate pub/sub layer. What you give up is portability and control over the execution environment. A graph framework runs wherever you can run Python or Node; this runs on Workers.
Within the Cloudflare ecosystem, the closest internal alternative is hand-rolling a Durable Object plus your own WebSocket protocol. That is what this SDK is abstracting, and the abstraction is the routing layer, the callable RPC, and the client hooks. If you only need one agent and one endpoint, the hand-rolled version is not much code. If you need MCP, scheduling, resumable streaming and per-user state together, the SDK earns its place.
Maintenance, releases and the MIT licence
The repository is not archived, and the last push was on 2026-09-10. Recent releases in the same window include [email protected] and @cloudflare/[email protected], both dated 2026-08-27. The version number matters more than the date: 0.22.0 is pre-1.0, so minor releases can carry breaking changes, and the README's own note about relocated ai-chat modules confirms that has happened. Budget time for upgrades rather than assuming they are drop-in.
The licence is MIT, and the repository also carries NOTICE, THIRD_PARTY_LICENSES.md and a licenses directory, which is what you would expect from a project that bundles or depends on third-party code. MIT is permissive, but the bundled dependencies have their own terms and the THIRD_PARTY_LICENSES.md file is where those are listed. Read it before you ship a product, and treat that as an engineering checklist item rather than a legal opinion.
The upgrade cost is mostly configuration drift. The README's example uses compatibility_date 2026-06-11 and the nodejs_compat flag. When you bump the SDK, check whether the required compatibility date moved, because a mismatch there produces runtime errors that look unrelated to the upgrade.
Editorial conclusion
Adopt cloudflare/agents if your team already ships Cloudflare Workers and you want per-user or per-session agent state without running your own session store. Do not adopt it if you need long CPU-bound jobs, since the README describes agents that hibernate when idle and wake on demand, which is a request-driven model rather than a batch compute service. Before committing, verify three things: that your wrangler.jsonc declares the Durable Object binding and the v1 SQLite migration, that your compatibility_date matches what the template ships, and that your AI provider keys are set as Worker secrets. The README does not document rollback, so decide how you will recover a bad deploy before you push one.
Frequently asked questions
How do I install cloudflare/agents?
Either scaffold the starter with npm create cloudflare@latest -- --template cloudflare/agents-starter, or run npm install agents in an existing project. Adding it to an existing Worker also requires a Durable Object binding and a SQLite migration in wrangler.jsonc.
How do I use cloudflare/agents in an existing Worker?
Subclass Agent with your environment and state types, mark methods with @callable(), and route requests through routeAgentRequest in your fetch handler. The README's example returns the routed response or falls through to a 404.
Does cloudflare/agents need a Durable Object binding?
Yes. The README states the agent is a Durable Object and shows both a durable_objects.bindings entry named after the class and a migrations entry with new_sqlite_classes in wrangler.jsonc.
What does the @cloudflare/voice package do?
The README describes it as a deprecated compatibility wrapper for the agents/voice exports. The voice capabilities themselves, including continuous STT, streaming TTS, VAD and interruption, are listed as features of the core agents package.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/cloudflare-agents)
Community notes