# Configuration 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: ```jsonc { "$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: ```jsonc "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: ```jsonc "durable_objects": { "bindings": [ { "name": "Counter", // Property name on `env` (env.Counter) "class_name": "Counter" // Exported class name (must match exactly) } ] } ``` | 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:** ```jsonc { "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: ```jsonc "migrations": [ { "tag": "v1", "new_sqlite_classes": ["MyAgent"] } ] ``` | Field | Description | | -------------------- | ------------------------------------------------------------- | | `tag` | Version identifier (e.g., "v1", "v2"). Must be unique | | `new_sqlite_classes` | Agent classes that use SQLite storage (state persistence) | | `deleted_classes` | Classes being removed | | `renamed_classes` | Classes being renamed (see [Migrations](#migrations-1) below) | #### assets For serving static files (HTML, CSS, JS): ```jsonc "assets": { "directory": "public", // Folder containing static files "binding": "ASSETS" // Optional: binding for programmatic access } ``` With a binding, you can serve assets programmatically: ```typescript 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 }); } }; ``` #### ai For Workers AI integration: ```jsonc "ai": { "binding": "AI", "remote": true // Mandatory: use remote inference (for local dev) } ``` Access in your agent: ```typescript const response = await this.env.AI.run("@cf/moonshotai/kimi-k2.5", { prompt: "Hello!" }); ``` ## Generating Types Wrangler can generate TypeScript types for your bindings. ### Automatic Generation Run the types command: ```bash npx wrangler types ``` This creates or updates `worker-configuration.d.ts` with your `Env` type. ### Custom Output Path Specify a custom path: ```bash npx wrangler types env.d.ts ``` ### Without Runtime Types For cleaner output (recommended for agents): ```bash npx wrangler types env.d.ts --include-runtime false ``` This generates just your bindings without Cloudflare runtime types. ### Example Generated Output ```typescript // 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: ```typescript // 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; ChatAgent: DurableObjectNamespace; // Other bindings AI: Ai; ASSETS: Fetcher; MY_KV: KVNamespace; } ``` ### Adding to package.json Add a script for easy regeneration: ```json { "scripts": { "types": "wrangler types env.d.ts --include-runtime false" } } ``` ## Environment Variables & Secrets ### Local Development (.env) Create a `.env` file for local secrets (add to `.gitignore`): ```bash # .env OPENAI_API_KEY=sk-... GITHUB_WEBHOOK_SECRET=whsec_... DATABASE_URL=postgres://... ``` Access in your agent: ```typescript class MyAgent extends Agent { async onStart() { const apiKey = process.env.OPENAI_API_KEY; } } ``` ### Production Secrets Use `wrangler secret` for production: ```bash # 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: ```jsonc { "vars": { "API_BASE_URL": "https://api.example.com", "MAX_RETRIES": "3", "DEBUG_MODE": "false" } } ``` Note: All values must be strings. Parse numbers/booleans in code: ```typescript const maxRetries = parseInt(process.env.MAX_RETRIES, 10); const debugMode = process.env.DEBUG_MODE === "true"; ``` ### Environment-Specific Variables Use `[env.{name}]` sections for different environments (e.g. staging, production): ```jsonc { "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: ```bash wrangler deploy --env staging wrangler deploy --env production ``` ## Local Development ### Starting the Dev Server With Vite (recommended for full stack apps): ```bash npx vite dev ``` Without Vite: ```bash npx wrangler dev ``` ### 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: ```bash rm -rf .wrangler/state ``` Or restart with fresh state: ```bash npx wrangler dev --persist-to="" ``` ### Inspecting Local SQLite You can inspect agent state directly: ```bash # 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 1. Go to [dash.cloudflare.com](https://dash.cloudflare.com) 2. Select your account → Workers & Pages 3. Click your Worker 4. 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: ```bash npx wrangler tail ``` Or in the dashboard: 1. Go to your Worker 2. Click **Logs** tab 3. 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 ```bash npx wrangler deploy ``` This: 1. Bundles your code 2. Uploads to Cloudflare 3. Applies migrations 4. Makes it live on `*.workers.dev` ### Custom Domain Add a route in wrangler.jsonc: ```jsonc { "routes": [ { "pattern": "agents.example.com/*", "zone_name": "example.com" } ] } ``` Or use a custom domain (simpler): ```jsonc { "routes": [ { "pattern": "agents.example.com", "custom_domain": true } ] } ``` ### Preview Deployments Deploy without affecting production: ```bash 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: ```bash npx wrangler rollback ``` ## Multi-Environment Setup ### Environment Configuration Define environments in wrangler.jsonc: ```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 ```bash # 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. To explicitly separate: ```jsonc { "env": { "staging": { "durable_objects": { "bindings": [ { "name": "MyAgent", "class_name": "MyAgent", "script_name": "my-agent-staging" // Different namespace } ] } } } } ``` ## Migrations Migrations manage Durable Object storage schema changes. ### Adding a New Agent Add to `new_sqlite_classes` in a new migration: ```jsonc "migrations": [ { "tag": "v1", "new_sqlite_classes": ["ExistingAgent"] }, { "tag": "v2", "new_sqlite_classes": ["NewAgent"] } ] ``` ### Renaming an Agent Class Use `renamed_classes`: ```jsonc "migrations": [ { "tag": "v1", "new_sqlite_classes": ["OldName"] }, { "tag": "v2", "renamed_classes": [ { "from": "OldName", "to": "NewName" } ] } ] ``` **Important:** Also update: 1. The class name in code 2. The `class_name` in bindings 3. Export statements ### Deleting an Agent Class Use `deleted_classes`: ```jsonc "migrations": [ { "tag": "v1", "new_sqlite_classes": ["AgentToDelete", "AgentToKeep"] }, { "tag": "v2", "deleted_classes": ["AgentToDelete"] } ] ``` **Warning:** This permanently deletes all data for that class. ### Migration Best Practices 1. **Never modify existing migrations** - Always add new ones 2. **Use sequential tags** - v1, v2, v3 (or use dates: 2025-01-15) 3. **Test locally first** - Migrations run on deploy 4. **Back up production data** - Before renaming or deleting ## Troubleshooting ### "No such Durable Object class" The class isn't in migrations: ```jsonc "migrations": [ { "tag": "v1", "new_sqlite_classes": ["MissingClassName"] // Add it here } ] ``` ### "Cannot find module" in types Regenerate types: ```bash npx wrangler types env.d.ts --include-runtime false ``` ### Secrets not loading locally Check that `.env` exists and contains the variable: ```bash cat .env # Should show: MY_SECRET=value ``` ### Migration tag conflict Migration tags must be unique. If you see conflicts: ```jsonc // Wrong - duplicate tags "migrations": [ { "tag": "v1", "new_sqlite_classes": ["A"] }, { "tag": "v1", "new_sqlite_classes": ["B"] } // Error! ] // Correct - sequential tags "migrations": [ { "tag": "v1", "new_sqlite_classes": ["A"] }, { "tag": "v2", "new_sqlite_classes": ["B"] } ] ```