# Wrangler Development Patterns Common workflows and best practices. ## New Worker Project ```bash wrangler init my-worker && cd my-worker wrangler dev # Develop locally wrangler deploy # Deploy ``` ## Local Development ```bash wrangler dev # Local mode (fast, simulated) wrangler dev --remote # Remote mode (production-accurate) wrangler dev --env staging --port 8787 wrangler dev --inspector-port 9229 # Enable debugging ``` Debug: chrome://inspect → Configure → localhost:9229 ## Secrets ```bash # Production echo "secret-value" | wrangler secret put SECRET_KEY # Local: use .dev.vars (gitignored) # SECRET_KEY=local-dev-key ``` ## Adding KV ```bash wrangler kv namespace create MY_KV wrangler kv namespace create MY_KV --preview # Add to wrangler.jsonc: { "binding": "MY_KV", "id": "abc123" } wrangler deploy ``` ## Adding D1 ```bash wrangler d1 create my-db wrangler d1 migrations create my-db "initial_schema" # Edit migration file in migrations/, then: wrangler d1 migrations apply my-db --local wrangler deploy wrangler d1 migrations apply my-db --remote # Time Travel (restore to point in time) wrangler d1 time-travel restore my-db --timestamp 2025-01-01T12:00:00Z ``` ## Multi-Environment ```bash wrangler deploy --env staging wrangler deploy --env production ``` ```jsonc { "env": { "staging": { "vars": { "ENV": "staging" } } } } ``` ## Testing ### Integration Tests with Node.js Test Runner ```typescript import { startWorker } from "wrangler"; import { describe, it, before, after } from "node:test"; import assert from "node:assert"; describe("API", () => { let worker; before(async () => { worker = await startWorker({ config: "wrangler.jsonc", remote: "minimal" // Fast tests with real bindings }); }); after(async () => await worker.dispose()); it("creates user", async () => { const response = await worker.fetch("http://example.com/api/users", { method: "POST", body: JSON.stringify({ name: "Alice" }) }); assert.strictEqual(response.status, 201); }); }); ``` ### Testing with Vitest Install: `npm install -D vitest @cloudflare/vitest-pool-workers` **vitest.config.ts:** ```typescript import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; export default defineWorkersConfig({ test: { poolOptions: { workers: { wrangler: { configPath: "./wrangler.jsonc" } } } } }); ``` **tests/api.test.ts:** ```typescript import { env, SELF } from "cloudflare:test"; import { describe, it, expect } from "vitest"; it("fetches users", async () => { const response = await SELF.fetch("https://example.com/api/users"); expect(response.status).toBe(200); }); it("uses bindings", async () => { await env.MY_KV.put("key", "value"); expect(await env.MY_KV.get("key")).toBe("value"); }); ``` ### Multi-Worker Development (Service Bindings) ```typescript const authWorker = await startWorker({ config: "./auth/wrangler.jsonc" }); const apiWorker = await startWorker({ config: "./api/wrangler.jsonc", bindings: { AUTH: authWorker } // Service binding }); // Test API calling AUTH const response = await apiWorker.fetch("http://example.com/api/protected"); await authWorker.dispose(); await apiWorker.dispose(); ``` ### Mock External APIs ```typescript const worker = await startWorker({ config: "wrangler.jsonc", outboundService: (req) => { const url = new URL(req.url); if (url.hostname === "api.external.com") { return new Response(JSON.stringify({ mocked: true }), { headers: { "content-type": "application/json" } }); } return fetch(req); // Pass through other requests } }); // Test Worker that calls external API const response = await worker.fetch("http://example.com/proxy"); // Worker internally fetches api.external.com - gets mocked response ``` ## Monitoring & Versions ```bash wrangler tail # Real-time logs wrangler tail --status error # Filter errors wrangler versions list wrangler rollback [id] ``` ## TypeScript ```bash wrangler types # Generate types from config ``` ```typescript export default { async fetch(request: Request, env: Env): Promise { return Response.json({ value: await env.MY_KV.get("key") }); } } satisfies ExportedHandler; ``` ## Workers Assets ```jsonc { "assets": { "directory": "./dist", "binding": "ASSETS" } } ``` ```typescript export default { async fetch(request, env) { // API routes first if (new URL(request.url).pathname.startsWith("/api/")) { return Response.json({ data: "from API" }); } return env.ASSETS.fetch(request); // Static assets } } ``` ## See Also - [README.md](./README.md) - Commands - [configuration.md](./configuration.md) - Config - [api.md](./api.md) - Programmatic API - [gotchas.md](./gotchas.md) - Issues