Documentation Index Fetch the complete documentation index at: https://mintlify.com/cloudflare/agents/llms.txt
Use this file to discover all available pages before exploring further.
This guide covers everything you need to configure agents for local development and production deployment, including wrangler.jsonc setup, type generation, environment variables, and the Cloudflare dashboard.
wrangler.jsonc
The wrangler.jsonc file configures your Cloudflare Worker and its bindings. Here’s a complete example for an agents project:
{
"$schema" : "node_modules/wrangler/config-schema.json" ,
"name" : "my-agent-app" ,
"main" : "src/server.ts" ,
"compatibility_date" : "2025-01-01" ,
"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"
}
]
},
// Required: Enable SQLite storage for agents
"migrations" : [
{
"tag" : "v1" ,
"new_sqlite_classes" : [ "MyAgent" , "ChatAgent" ]
}
],
// AI binding (optional, for Workers AI)
"ai" : {
"binding" : "AI"
}
}
Key Fields
compatibility_flags
The nodejs_compat flag is required for agents:
"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" , // Property name on `env` (env.Counter)
"class_name" : "Counter" // Exported class name (must match exactly)
}
]
}
Field Description nameThe property name on env. Use this in code: env.Counter class_nameMust match the exported class name exactly
When name and class_name differ:
{
"name" : "COUNTER_DO" , // env.COUNTER_DO
"class_name" : "CounterAgent" // export class CounterAgent
}
This is useful when you want environment variable-style naming (COUNTER_DO) but more descriptive class names (CounterAgent).
migrations
Migrations tell Cloudflare how to set up storage for your Durable Objects:
"migrations" : [
{
"tag" : "v1" ,
"new_sqlite_classes" : [ "MyAgent" ]
}
]
Field Description tagVersion identifier (e.g., “v1”, “v2”). Must be unique new_sqlite_classesAgent classes that use SQLite storage (state persistence) deleted_classesClasses being removed renamed_classesClasses being renamed
assets
For serving static files (HTML, CSS, JS):
"assets" : {
"directory" : "public" , // Folder containing static files
"binding" : "ASSETS" // Optional: binding for programmatic access
}
With a binding, you can serve assets programmatically:
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 if you want to handle requests that are not for agents
return new Response ( "Not found" , { status: 404 });
}
} ;
For Workers AI integration:
"ai" : {
"binding" : "AI" ,
"remote" : true // Mandatory: use remote inference (for local dev)
}
Access in your agent:
const response = await this . env . AI . run ( "@cf/zai-org/glm-4.7-flash" , {
prompt: "Hello!"
});
Generating Types
Wrangler can generate TypeScript types for your bindings.
Automatic Generation
Run the types command:
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
// Generated by wrangler
declare namespace Cloudflare {
interface Env {
OPENAI_API_KEY : string ;
Counter : DurableObjectNamespace < import ( "./src/server" ). Counter >;
ChatAgent : DurableObjectNamespace < import ( "./src/server" ). ChatAgent >;
}
}
interface Env extends Cloudflare . Env {}
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):
OPENAI_API_KEY = sk-...
GITHUB_WEBHOOK_SECRET = whsec_...
DATABASE_URL = postgres://...
Access in your agent:
class MyAgent extends Agent < Env > {
async onStart () {
const apiKey = process . env . OPENAI_API_KEY ;
}
}
Production Secrets
Use wrangler secret for production:
# Add a secret
wrangler secret put OPENAI_API_KEY
# Enter value when prompted
# List secrets
wrangler secret list
# Delete a secret
wrangler secret delete OPENAI_API_KEY
Non-Secret Variables
For non-sensitive configuration, use vars in wrangler.jsonc:
{
"vars" : {
"API_BASE_URL" : "https://api.example.com" ,
"MAX_RETRIES" : "3" ,
"DEBUG_MODE" : "false"
}
}
All values must be strings. Parse numbers/booleans in code: const maxRetries = parseInt ( process . env . MAX_RETRIES , 10 );
const debugMode = process . env . DEBUG_MODE === "true" ;
Environment-Specific Variables
Use env sections for different environments (e.g. 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"
}
}
}
}
Deploy to specific environment:
wrangler deploy --env staging
wrangler deploy --env production
Local Development
Starting the Dev Server
With Vite (recommended for full stack apps):
Without Vite:
Local State Persistence
Durable Object state is persisted locally in .wrangler/state/:
.wrangler/
└── state/
└── v3/
└── d1/
└── miniflare-D1DatabaseObject/
└── ... (SQLite files)
Clearing Local State
To reset all local Durable Object state:
Or restart with fresh state:
npx wrangler dev --persist-to= ""
Inspecting Local SQLite
You can inspect agent state directly:
# Find the SQLite file
ls .wrangler/state/v3/d1/
# Open with sqlite3
sqlite3 .wrangler/state/v3/d1/miniflare-D1DatabaseObject/ * .sqlite
Dashboard Setup
Automatic Resources
When you deploy, Cloudflare automatically creates:
Worker - Your deployed code
Durable Object namespaces - One per agent class
SQLite storage - Attached to each namespace
Viewing Durable Objects
Go to Cloudflare Dashboard
Select Workers and Pages
Select your account → Workers & Pages
Click your Worker
Click your Worker name
View Durable Objects
Go to Durable Objects tab
Here you can:
See all Durable Object namespaces
View individual object instances
Inspect storage (keys and values)
Delete objects
Real-time Logs
View live logs from your agents:
Or in the dashboard:
Go to your Worker
Click Logs tab
Enable real-time logs
Filter by:
Status (success, error)
Search text
Sampling rate
Analytics
The dashboard shows:
Request count
Error rate
CPU time
Duration percentiles
Durable Object metrics
Production Deployment
Basic Deploy
This:
Bundles your code
Uploads to Cloudflare
Applies migrations
Makes it live on *.workers.dev
Custom Domain
Add a route in wrangler.jsonc:
{
"routes" : [
{
"pattern" : "agents.example.com/*" ,
"zone_name" : "example.com"
}
]
}
Or use a custom domain (simpler):
{
"routes" : [
{
"pattern" : "agents.example.com" ,
"custom_domain" : true
}
]
}
Preview Deployments
Deploy without affecting production:
npx wrangler deploy --dry-run # See what would be uploaded
npx wrangler versions upload # Upload new version
npx wrangler versions deploy # Gradually roll out
Rollbacks
Roll back to a previous version:
Multi-Environment Setup
Environment Configuration
Define environments in wrangler.jsonc:
{
"name" : "my-agent" ,
"main" : "src/server.ts" ,
// Base configuration (shared)
"compatibility_date" : "2025-01-01" ,
"compatibility_flags" : [ "nodejs_compat" ],
"durable_objects" : {
"bindings" : [{ "name" : "MyAgent" , "class_name" : "MyAgent" }]
},
"migrations" : [{ "tag" : "v1" , "new_sqlite_classes" : [ "MyAgent" ] }],
// Environment overrides
"env" : {
"staging" : {
"name" : "my-agent-staging" ,
"vars" : {
"ENVIRONMENT" : "staging"
}
},
"production" : {
"name" : "my-agent-production" ,
"vars" : {
"ENVIRONMENT" : "production"
}
}
}
}
Deploying to Environments
# Deploy to staging
npx wrangler deploy --env staging
# Deploy to production
npx wrangler deploy --env production
# Set secrets per environment
npx wrangler secret put OPENAI_API_KEY --env staging
npx wrangler secret put OPENAI_API_KEY --env production
Separate Durable Objects
Each environment gets its own Durable Objects. Staging agents don’t share state with production agents.
Migrations
Migrations manage Durable Object storage schema changes.
Adding a New Agent
Add to new_sqlite_classes in a new migration:
"migrations" : [
{
"tag" : "v1" ,
"new_sqlite_classes" : [ "ExistingAgent" ]
},
{
"tag" : "v2" ,
"new_sqlite_classes" : [ "NewAgent" ]
}
]
Renaming an Agent Class
Use renamed_classes:
"migrations" : [
{
"tag" : "v1" ,
"new_sqlite_classes" : [ "OldName" ]
},
{
"tag" : "v2" ,
"renamed_classes" : [
{
"from" : "OldName" ,
"to" : "NewName"
}
]
}
]
Important: Also update:
The class name in code
The class_name in bindings
Export statements
Deleting an Agent Class
Use deleted_classes:
"migrations" : [
{
"tag" : "v1" ,
"new_sqlite_classes" : [ "AgentToDelete" , "AgentToKeep" ]
},
{
"tag" : "v2" ,
"deleted_classes" : [ "AgentToDelete" ]
}
]
This permanently deletes all data for that class.
Migration Best Practices
Never modify existing migrations - Always add new ones
Use sequential tags - v1, v2, v3 (or use dates: 2025-01-15)
Test locally first - Migrations run on deploy
Back up production data - Before renaming or deleting
Troubleshooting
”No such Durable Object class”
The class isn’t in migrations:
"migrations" : [
{
"tag" : "v1" ,
"new_sqlite_classes" : [ "MissingClassName" ] // Add it here
}
]
“Cannot find module” in types
Regenerate types:
npx wrangler types env.d.ts --include-runtime false
Secrets not loading locally
Check that .env exists and contains the variable:
cat .env
# Should show: MY_SECRET=value
Migration tag conflict
Migration tags must be unique. If you see conflicts:
Wrong - Duplicate Tags
Correct - Sequential Tags
// Wrong - duplicate tags
"migrations" : [
{ "tag" : "v1" , "new_sqlite_classes" : [ "A" ] },
{ "tag" : "v1" , "new_sqlite_classes" : [ "B" ] } // Error!
]