Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Comprehensive Cloudflare platform skill covering Workers, D1, R2, KV, AI, Durable Objects, and security.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/workers-for-platforms/patterns.md
1# Multi-Tenant Patterns23## Billing by Plan45```typescript6interface Env {7DISPATCHER: DispatchNamespace;8CUSTOMERS_KV: KVNamespace;9}1011export default {12async fetch(request: Request, env: Env): Promise<Response> {13const userWorkerName = new URL(request.url).hostname.split(".")[0];14const customerPlan = await env.CUSTOMERS_KV.get(userWorkerName);1516const plans = {17enterprise: { cpuMs: 50, subRequests: 50 },18pro: { cpuMs: 20, subRequests: 20 },19free: { cpuMs: 10, subRequests: 5 },20};21const limits = plans[customerPlan as keyof typeof plans] || plans.free;2223const userWorker = env.DISPATCHER.get(userWorkerName, {}, { limits });24return await userWorker.fetch(request);25},26};27```2829## Resource Isolation3031**Complete isolation:** Create unique resources per customer32- KV namespace per customer33- D1 database per customer34- R2 bucket per customer3536```typescript37const bindings = [{38type: "kv_namespace",39name: "USER_KV",40namespace_id: `customer-${customerId}-kv`41}];42```4344## Hostname Routing4546### Wildcard Route (Recommended)47Configure `*/*` route on SaaS domain → dispatch Worker4849**Benefits:**50- Supports subdomains + custom vanity domains51- No per-route limits (regular Workers limited to 100 routes)52- Programmatic control53- Works with any DNS proxy settings5455**Setup:**561. Cloudflare for SaaS custom hostnames572. Fallback origin (dummy `A 192.0.2.0` if Worker is origin)583. DNS CNAME to SaaS domain594. `*/*` route → dispatch Worker605. Routing logic in dispatch Worker6162```typescript63export default {64async fetch(request: Request, env: Env): Promise<Response> {65const hostname = new URL(request.url).hostname;66const hostnameData = await env.ROUTING_KV.get(`hostname:${hostname}`, { type: "json" });6768if (!hostnameData?.workerName) {69return new Response("Hostname not configured", { status: 404 });70}7172const userWorker = env.DISPATCHER.get(hostnameData.workerName);73return await userWorker.fetch(request);74},75};76```7778### Subdomain-Only791. Wildcard DNS: `*.saas.com` → origin802. Route: `*.saas.com/*` → dispatch Worker813. Extract subdomain for routing8283### Orange-to-Orange (O2O) Behavior8485When customers use Cloudflare and CNAME to your Workers domain:8687| Scenario | Behavior | Route Pattern |88|----------|----------|---------------|89| Customer not on Cloudflare | Standard routing | `*/*` or `*.domain.com/*` |90| Customer on Cloudflare (proxied CNAME) | Invokes Worker at edge | `*/*` required |91| Customer on Cloudflare (DNS-only CNAME) | Standard routing | Any route works |9293**Recommendation:** Always use `*/*` wildcard for consistent O2O behavior.9495### Custom Metadata Routing9697For 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.9899## Observability100101### Logpush102- Enable on dispatch Worker → captures all user Worker logs103- Filter by `Outcome` or `Script Name`104105### Tail Workers106- Real-time logs with custom formatting107- Receives HTTP status, `console.log()`, exceptions, diagnostics108109### Analytics Engine110```typescript111// Track violations112env.ANALYTICS.writeDataPoint({113indexes: [customerName],114blobs: ["cpu_limit_exceeded"],115});116```117118### GraphQL119```graphql120query {121viewer {122accounts(filter: {accountTag: $accountId}) {123workersInvocationsAdaptive(filter: {dispatchNamespaceName: "production"}) {124sum { requests errors cpuTime }125}126}127}128}129```130131## Use Case Implementations132133### AI Code Execution134```typescript135async function deployGeneratedCode(name: string, code: string) {136const file = new File([code], `${name}.mjs`, { type: "application/javascript+module" });137await client.workersForPlatforms.dispatch.namespaces.scripts.update("production", name, {138account_id: accountId,139metadata: { main_module: `${name}.mjs`, tags: [name, "ai-generated"] },140files: [file],141});142}143144// Short limits for untrusted code145const userWorker = env.DISPATCHER.get(sessionId, {}, { limits: { cpuMs: 5, subRequests: 3 } });146```147148**VibeSDK:** For AI-powered code generation + deployment platforms, see [VibeSDK](https://github.com/cloudflare/vibesdk) - handles AI generation, sandbox execution, live preview, and deployment.149150Reference: [AI Vibe Coding Platform Architecture](https://developers.cloudflare.com/reference-architecture/diagrams/ai/ai-vibe-coding-platform/)151152### Edge Functions Platform153```typescript154// Route: /customer-id/function-name155const [customerId, functionName] = new URL(request.url).pathname.split("/").filter(Boolean);156const workerName = `${customerId}-${functionName}`;157const userWorker = env.DISPATCHER.get(workerName);158```159160### Website Builder161- Deploy static assets + Worker code162- See [api.md](./api.md#static-assets) for full implementation163- Salt hashes for asset isolation164165## Best Practices166167### Architecture168- One namespace per environment (production, staging)169- Platform logic in dispatch Worker (auth, rate limiting, validation)170- Isolation automatic (no shared cache, untrusted mode)171172### Routing173- Use `*/*` wildcard routes174- Store mappings in KV175- Handle missing Workers gracefully176177### Limits & Security178- Set custom limits by plan179- Track violations with Analytics Engine180- Use outbound Workers for egress control181- Sanitize responses182183### Tags184- Tag all Workers: customer ID, plan, environment185- Enable bulk operations186- Filter efficiently187188See [README.md](./README.md), [configuration.md](./configuration.md), [api.md](./api.md), [gotchas.md](./gotchas.md)189