Configuration (5)
Last updated Oct 12, 2026 This guide covers everything you need to configure agents for local development and production deployment, including Wrangler configuration file setup, type generation, environment variables, and the Cloudflare dashboard.
Project structure
The typical file structure for an Agent project created from npm create cloudflare@latest agents-starter -- --template cloudflare/agents-starter follows:
- src/
- index.ts your Agent definition
- public/
- index.html
- test/
- index.spec.ts your tests
- package.json
- tsconfig.json
- vitest.config.mts
- worker-configuration.d.ts
- wrangler.jsonc your Workers and Agent configuration
Wrangler configuration file
The wrangler.jsonc file configures your Cloudflare Worker and its bindings. Here is a complete example for an agents project:
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-agent-app",
"main": "src/server.ts",
"upload_source_maps": true,
// Set this to today's date
"compatibility_date": "2026-10-27",
"compatibility_flags": ["nodejs_compat"],
// Static assets (optional)
"assets": {
"directory": "public",
"binding": "ASSETS",
},
// Durable Object bindings for agents
"durable_objects": {
"bindings": [
{
"name": "MyAgent",
"class_name": "MyAgent",
},
{
"name": "ChatAgent",
"class_name": "ChatAgent",
},
],
},
// Provision storage for each agent class
"exports": {
"MyAgent": {
"type": "durable-object",
"storage": "sqlite",
},
"ChatAgent": {
"type": "durable-object",
"storage": "sqlite",
},
},
// AI binding (optional, for Workers AI)
"ai": {
"binding": "AI",
},
// Observability (recommended)
"observability": {
"enabled": true,
},
}
"$schema" = "node_modules/wrangler/config-schema.json"
name = "my-agent-app"
main = "src/server.ts"
upload_source_maps = true
# Set this to today's date
compatibility_date = "2026-10-27"
compatibility_flags = [ "nodejs_compat" ]
[assets]
directory = "public"
binding = "ASSETS"
[[durable_objects.bindings]]
name = "MyAgent"
class_name = "MyAgent"
[[durable_objects.bindings]]
name = "ChatAgent"
class_name = "ChatAgent"
[exports.MyAgent]
type = "durable-object"
storage = "sqlite"
[exports.ChatAgent]
type = "durable-object"
storage = "sqlite"
[ai]
binding = "AI"
[observability]
enabled = true
Key fields
compatibility_flags
The nodejs_compat flag is required for agents:
{
"compatibility_flags": ["nodejs_compat"],
}
compatibility_flags = [ "nodejs_compat" ]
This enables Node.js compatibility mode, which agents depend on for crypto, streams, and other Node.js APIs.
durable_objects.bindings
Each agent class needs a binding:
{
"durable_objects": {
"bindings": [
{
"name": "Counter",
"class_name": "Counter",
},
],
},
}
[[durable_objects.bindings]]
name = "Counter"
class_name = "Counter"
| Field | Description |
|---|---|
name |
The property name on env. Use this in code: env.Counter |
class_name |
Must match the exported class name exactly |
When `name` and `class_name` differ
When name and class_name differ, follow the pattern shown below:
{
"durable_objects": {
"bindings": [
{
"name": "COUNTER_DO",
"class_name": "CounterAgent",
},
],
},
}
[[durable_objects.bindings]]
name = "COUNTER_DO"
class_name = "CounterAgent"
This is useful when you want environment variable-style naming (COUNTER_DO) but more descriptive class names (CounterAgent).
exports
The exports field declares each Agent class your Worker exports and the storage backend Cloudflare should use for it:
{
"exports": {
"MyAgent": {
"type": "durable-object",
"storage": "sqlite",
},
},
}
[exports.MyAgent]
type = "durable-object"
storage = "sqlite"
| Field | Description |
|---|---|
type |
The kind of export. Always "durable-object" for an Agent. |
storage |
The storage backend. Use "sqlite" for new Agents (recommended). |
For details on renaming, deleting, or transferring Agent classes, refer to Durable Object class exports. Existing Workers using the legacy migrations array continue to work — refer to Durable Object class migrations (legacy).
assets
For serving static files (HTML, CSS, JS):
{
"assets": {
"directory": "public",
"binding": "ASSETS",
},
}
[assets]
directory = "public"
binding = "ASSETS"
With a binding, you can serve assets programmatically:
export default {
async fetch(request, env) {
// Static assets are served by the worker automatically by default
// Route the request to the appropriate agent
const agentResponse = await routeAgentRequest(request, env);
if (agentResponse) return agentResponse;
// Add your own routing logic here
return new Response("Not found", { status: 404 });
},
};
export default {
async fetch(request: Request, env: Env) {
// Static assets are served by the worker automatically by default
// Route the request to the appropriate agent
const agentResponse = await routeAgentRequest(request, env);
if (agentResponse) return agentResponse;
// Add your own routing logic here
return new Response("Not found", { status: 404 });
},
} satisfies ExportedHandler<Env>;
ai
For Workers AI integration:
{
"ai": {
"binding": "AI",
},
}
[ai]
binding = "AI"
Access in your agent:
const response = await this.env.AI.run("@cf/meta/llama-3-8b-instruct", {
prompt: "Hello!",
});
const response = await this.env.AI.run("@cf/meta/llama-3-8b-instruct", {
prompt: "Hello!",
});
TypeScript configuration
The Agents SDK ships a shared tsconfig.json that sets all the compiler options needed for agents projects — including the ES2021 target required for @callable() decorators, strict mode, bundler module resolution, and Workers types.
Extend it in your tsconfig.json:
{
"extends": "agents/tsconfig"
}
This is equivalent to:
{
"compilerOptions": {
"target": "ES2021",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"jsx": "react-jsx",
"module": "ES2022",
"moduleResolution": "bundler",
"types": ["node", "@cloudflare/workers-types", "vite/client"],
"allowImportingTsExtensions": true,
"noEmit": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
You can override individual options as needed:
{
"extends": "agents/tsconfig",
"compilerOptions": {
"jsx": "preserve"
}
}
Caution
Do not set "experimentalDecorators": true. The Agents SDK uses TC39 standard decorators ↗︎, not TypeScript legacy decorators. Enabling experimentalDecorators applies an incompatible transform that silently breaks @callable() at runtime.
Vite configuration
The Agents SDK provides a Vite plugin that handles TC39 decorator transforms. Vite 8 uses Oxc for transpilation, which does not yet support TC39 decorators — without this plugin, @callable() and other decorators will fail at runtime.
Add the plugin to your vite.config.ts:
import { cloudflare } from "@cloudflare/vite-plugin";
import react from "@vitejs/plugin-react";
import agents from "agents/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [agents(), react(), cloudflare()],
});
vite.config.tsts
import { cloudflare } from "@cloudflare/vite-plugin";
import react from "@vitejs/plugin-react";
import agents from "agents/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [agents(), react(), cloudflare()],
});
The agents() plugin is safe to include even if your project does not use decorators. It only runs the transform on files that contain @ syntax.
The starter template and all examples include this plugin by default. If you encounter SyntaxError: Invalid or unexpected token with decorators, refer to Callable methods — Troubleshooting.
Generating types
Wrangler can generate TypeScript types for your bindings.
Automatic generation
Run the types command:
npx wrangler types
This creates or updates worker-configuration.d.ts with your Env type.
Custom output path
Specify a custom path:
npx wrangler types env.d.ts
Without runtime types
For cleaner output (recommended for agents):
npx wrangler types env.d.ts --include-runtime false
This generates just your bindings without Cloudflare runtime types.
Example generated output
// env.d.ts (generated)
declare namespace Cloudflare {
interface Env {
OPENAI_API_KEY: string;
Counter: DurableObjectNamespace;
ChatAgent: DurableObjectNamespace;
}
}
interface Env extends Cloudflare.Env {}
Manual type definition
You can also define types manually:
// env.d.ts
// env.d.ts
import type { Counter } from "./src/agents/counter";
import type { ChatAgent } from "./src/agents/chat";
interface Env {
// Secrets
OPENAI_API_KEY: string;
WEBHOOK_SECRET: string;
// Agent bindings
Counter: DurableObjectNamespace<Counter>;
ChatAgent: DurableObjectNamespace<ChatAgent>;
// Other bindings
AI: Ai;
ASSETS: Fetcher;
MY_KV: KVNamespace;
}
Adding to package.json
Add a script for easy regeneration:
{
"scripts": {
"types": "wrangler types env.d.ts --include-runtime false"
}
}
Environment variables and secrets
Local development (.env)
Create a .env file for local secrets (add to .gitignore):
# .env
OPENAI_API_KEY=sk-...
GITHUB_WEBHOOK_SECRET=whsec_...
DATABASE_URL=postgres://...
Access in your agent:
class MyAgent extends Agent {
async onStart() {
const apiKey = this.env.OPENAI_API_KEY;
}
}
class MyAgent extends Agent {
async onStart() {
const apiKey = this.env.OPENAI_API_KEY;
}
}
Production secrets
Use wrangler secret for production:
# Add a secret
npx wrangler secret put OPENAI_API_KEY
# Enter value when prompted
# List secrets
npx wrangler secret list
# Delete a secret
npx wrangler secret delete OPENAI_API_KEY
Non-secret variables
For non-sensitive configuration, use vars in the Wrangler configuration file:
{
"vars": {
"API_BASE_URL": "https://api.example.com",
"MAX_RETRIES": "3",
"DEBUG_MODE": "false",
},
}
[vars]
API_BASE_URL = "https://api.example.com"
MAX_RETRIES = "3"
DEBUG_MODE = "false"
All values must be strings. Parse numbers and booleans in code:
const maxRetries = parseInt(this.env.MAX_RETRIES, 10);
const debugMode = this.env.DEBUG_MODE === "true";
const maxRetries = parseInt(this.env.MAX_RETRIES, 10);
const debugMode = this.env.DEBUG_MODE === "true";
Environment-specific variables
Use env sections for different environments (for example, staging, production):
{
"name": "my-agent",
"vars": {
"API_URL": "https://api.example.com",
},
"env": {
"staging": {
"vars": {
"API_URL": "https://staging-api.example.com",
},
},
"production": {
"vars": {
"API_URL": "https://api.example.com",
},
},
},
}
name = "my-agent"
[vars]
API_URL = "https://api.example.com"
[env.staging.vars]
API_URL = "https://staging-api.example.com"
[env.production.vars]
API_URL = "https://api.example.com"
Deploy to specific environment:
npx wrangler deploy --env staging
npx wrangler deploy --env production
