# Architecture Patterns ## Component Resources ```typescript class WorkerApp extends pulumi.ComponentResource { constructor(name: string, args: WorkerAppArgs, opts?) { super("custom:cloudflare:WorkerApp", name, {}, opts); const defaultOpts = {parent: this}; this.kv = new cloudflare.WorkersKvNamespace(`${name}-kv`, {accountId: args.accountId, title: `${name}-kv`}, defaultOpts); this.worker = new cloudflare.WorkerScript(`${name}-worker`, { accountId: args.accountId, name: `${name}-worker`, content: args.workerCode, module: true, kvNamespaceBindings: [{name: "KV", namespaceId: this.kv.id}], }, defaultOpts); this.domain = new cloudflare.WorkersDomain(`${name}-domain`, { accountId: args.accountId, hostname: args.domain, service: this.worker.name, }, defaultOpts); } } ``` ## Full-Stack Worker App ```typescript const kv = new cloudflare.WorkersKvNamespace("cache", {accountId, title: "api-cache"}); const db = new cloudflare.D1Database("db", {accountId, name: "app-database"}); const bucket = new cloudflare.R2Bucket("assets", {accountId, name: "app-assets"}); const apiWorker = new cloudflare.WorkerScript("api", { accountId, name: "api-worker", content: fs.readFileSync("./dist/api.js", "utf8"), module: true, kvNamespaceBindings: [{name: "CACHE", namespaceId: kv.id}], d1DatabaseBindings: [{name: "DB", databaseId: db.id}], r2BucketBindings: [{name: "ASSETS", bucketName: bucket.name}], }); ``` ## Multi-Environment Setup ```typescript const stack = pulumi.getStack(); const worker = new cloudflare.WorkerScript(`worker-${stack}`, { accountId, name: `my-worker-${stack}`, content: code, plainTextBindings: [{name: "ENVIRONMENT", text: stack}], }); ``` ## Queue-Based Processing ```typescript const queue = new cloudflare.Queue("processing-queue", {accountId, name: "image-processing"}); // Producer: API receives requests const apiWorker = new cloudflare.WorkerScript("api", { accountId, name: "api-worker", content: apiCode, queueBindings: [{name: "PROCESSING_QUEUE", queue: queue.id}], }); // Consumer: Process async const processorWorker = new cloudflare.WorkerScript("processor", { accountId, name: "processor-worker", content: processorCode, queueConsumers: [{queue: queue.name, maxBatchSize: 10, maxRetries: 3, maxWaitTimeMs: 5000}], r2BucketBindings: [{name: "OUTPUT_BUCKET", bucketName: outputBucket.name}], }); ``` ## Microservices with Service Bindings ```typescript const authWorker = new cloudflare.WorkerScript("auth", {accountId, name: "auth-service", content: authCode}); const apiWorker = new cloudflare.WorkerScript("api", { accountId, name: "api-service", content: apiCode, serviceBindings: [{name: "AUTH", service: authWorker.name}], }); ``` ## Event-Driven Architecture ```typescript const eventQueue = new cloudflare.Queue("events", {accountId, name: "event-bus"}); const producer = new cloudflare.WorkerScript("producer", { accountId, name: "api-producer", content: producerCode, queueBindings: [{name: "EVENTS", queue: eventQueue.id}], }); const consumer = new cloudflare.WorkerScript("consumer", { accountId, name: "email-consumer", content: consumerCode, queueConsumers: [{queue: eventQueue.name, maxBatchSize: 10}], }); ``` ## v6.x Versioned Deployments (Blue-Green/Canary) ```typescript const worker = new cloudflare.Worker("api", {accountId, name: "api-worker"}); const v1 = new cloudflare.WorkerVersion("v1", {accountId, workerId: worker.id, content: fs.readFileSync("./dist/v1.js", "utf8"), compatibilityDate: "2025-01-01"}); const v2 = new cloudflare.WorkerVersion("v2", {accountId, workerId: worker.id, content: fs.readFileSync("./dist/v2.js", "utf8"), compatibilityDate: "2025-01-01"}); // Gradual rollout: 10% v2, 90% v1 const deployment = new cloudflare.WorkersDeployment("canary", { accountId, workerId: worker.id, versions: [{versionId: v2.id, percentage: 10}, {versionId: v1.id, percentage: 90}], kvNamespaceBindings: [{name: "MY_KV", namespaceId: kv.id}], }); ``` **Use:** Canary releases, A/B testing, blue-green. Most apps use `WorkerScript` (auto-versioning). ## Wrangler.toml Generation (Bridge IaC with Local Dev) Generate wrangler.toml from Pulumi config to keep local dev in sync: ```typescript import * as command from "@pulumi/command"; const workerConfig = { name: "my-worker", compatibilityDate: "2025-01-01", compatibilityFlags: ["nodejs_compat"], }; // Create resources const kv = new cloudflare.WorkersKvNamespace("kv", {accountId, title: "my-kv"}); const db = new cloudflare.D1Database("db", {accountId, name: "my-db"}); const bucket = new cloudflare.R2Bucket("bucket", {accountId, name: "my-bucket"}); // Generate wrangler.toml after resources created const wranglerGen = new command.local.Command("gen-wrangler", { create: pulumi.interpolate`cat > wrangler.toml < fs.readFileSync("./worker/dist/index.js", "utf8")), }, {dependsOn: [build]}); ``` ## Content SHA Pattern (Force Updates) Prevent false "no changes" detections: ```typescript const version = Date.now().toString(); const worker = new cloudflare.WorkerScript("worker", { accountId, name: "my-worker", content: code, plainTextBindings: [{name: "VERSION", text: version}], // Forces deployment }); ``` --- See: [README.md](./README.md), [configuration.md](./configuration.md), [api.md](./api.md), [gotchas.md](./gotchas.md)