Files
dotfiles/.agents/skills/cloudflare-deploy/references/workers-for-platforms/patterns.md
2026-03-17 16:53:22 -07:00

5.5 KiB

Multi-Tenant Patterns

Billing by Plan

interface Env {
  DISPATCHER: DispatchNamespace;
  CUSTOMERS_KV: KVNamespace;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const userWorkerName = new URL(request.url).hostname.split(".")[0];
    const customerPlan = await env.CUSTOMERS_KV.get(userWorkerName);
    
    const plans = {
      enterprise: { cpuMs: 50, subRequests: 50 },
      pro: { cpuMs: 20, subRequests: 20 },
      free: { cpuMs: 10, subRequests: 5 },
    };
    const limits = plans[customerPlan as keyof typeof plans] || plans.free;
    
    const userWorker = env.DISPATCHER.get(userWorkerName, {}, { limits });
    return await userWorker.fetch(request);
  },
};

Resource Isolation

Complete isolation: Create unique resources per customer

  • KV namespace per customer
  • D1 database per customer
  • R2 bucket per customer
const bindings = [{
  type: "kv_namespace",
  name: "USER_KV",
  namespace_id: `customer-${customerId}-kv`
}];

Hostname Routing

Configure */* route on SaaS domain → dispatch Worker

Benefits:

  • Supports subdomains + custom vanity domains
  • No per-route limits (regular Workers limited to 100 routes)
  • Programmatic control
  • Works with any DNS proxy settings

Setup:

  1. Cloudflare for SaaS custom hostnames
  2. Fallback origin (dummy A 192.0.2.0 if Worker is origin)
  3. DNS CNAME to SaaS domain
  4. */* route → dispatch Worker
  5. Routing logic in dispatch Worker
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const hostname = new URL(request.url).hostname;
    const hostnameData = await env.ROUTING_KV.get(`hostname:${hostname}`, { type: "json" });
    
    if (!hostnameData?.workerName) {
      return new Response("Hostname not configured", { status: 404 });
    }
    
    const userWorker = env.DISPATCHER.get(hostnameData.workerName);
    return await userWorker.fetch(request);
  },
};

Subdomain-Only

  1. Wildcard DNS: *.saas.com → origin
  2. Route: *.saas.com/* → dispatch Worker
  3. Extract subdomain for routing

Orange-to-Orange (O2O) Behavior

When customers use Cloudflare and CNAME to your Workers domain:

Scenario Behavior Route Pattern
Customer not on Cloudflare Standard routing */* or *.domain.com/*
Customer on Cloudflare (proxied CNAME) Invokes Worker at edge */* required
Customer on Cloudflare (DNS-only CNAME) Standard routing Any route works

Recommendation: Always use */* wildcard for consistent O2O behavior.

Custom Metadata Routing

For Cloudflare for SaaS: Store worker name in custom hostname custom_metadata, retrieve in dispatch worker to route requests. Requires custom hostnames as subdomains of your domain.

Observability

Logpush

  • Enable on dispatch Worker → captures all user Worker logs
  • Filter by Outcome or Script Name

Tail Workers

  • Real-time logs with custom formatting
  • Receives HTTP status, console.log(), exceptions, diagnostics

Analytics Engine

// Track violations
env.ANALYTICS.writeDataPoint({
  indexes: [customerName],
  blobs: ["cpu_limit_exceeded"],
});

GraphQL

query {
  viewer {
    accounts(filter: {accountTag: $accountId}) {
      workersInvocationsAdaptive(filter: {dispatchNamespaceName: "production"}) {
        sum { requests errors cpuTime }
      }
    }
  }
}

Use Case Implementations

AI Code Execution

async function deployGeneratedCode(name: string, code: string) {
  const file = new File([code], `${name}.mjs`, { type: "application/javascript+module" });
  await client.workersForPlatforms.dispatch.namespaces.scripts.update("production", name, {
    account_id: accountId,
    metadata: { main_module: `${name}.mjs`, tags: [name, "ai-generated"] },
    files: [file],
  });
}

// Short limits for untrusted code
const userWorker = env.DISPATCHER.get(sessionId, {}, { limits: { cpuMs: 5, subRequests: 3 } });

VibeSDK: For AI-powered code generation + deployment platforms, see VibeSDK - handles AI generation, sandbox execution, live preview, and deployment.

Reference: AI Vibe Coding Platform Architecture

Edge Functions Platform

// Route: /customer-id/function-name
const [customerId, functionName] = new URL(request.url).pathname.split("/").filter(Boolean);
const workerName = `${customerId}-${functionName}`;
const userWorker = env.DISPATCHER.get(workerName);

Website Builder

  • Deploy static assets + Worker code
  • See api.md for full implementation
  • Salt hashes for asset isolation

Best Practices

Architecture

  • One namespace per environment (production, staging)
  • Platform logic in dispatch Worker (auth, rate limiting, validation)
  • Isolation automatic (no shared cache, untrusted mode)

Routing

  • Use */* wildcard routes
  • Store mappings in KV
  • Handle missing Workers gracefully

Limits & Security

  • Set custom limits by plan
  • Track violations with Analytics Engine
  • Use outbound Workers for egress control
  • Sanitize responses

Tags

  • Tag all Workers: customer ID, plan, environment
  • Enable bulk operations
  • Filter efficiently

See README.md, configuration.md, api.md, gotchas.md