This site is not affiliated with or endorsed by Cloudflare, Inc. It showcases deployable experiments across most Cloudflare products.
Compute & Isolation

User Script Dispatcher

Workers for Platforms-style dispatch via Dispatch Namespace or KV-stored handlers - multi-tenant user Worker routing

Workers for Platforms style dispatch - register customers and run tenant response handlers via a DispatchNamespace binding, with a KV fallback for local demos. Stored scripts return a fixed JSON response (safe demo - no dynamic JS eval).

API Reference

POST /scripts

Store a JSON response handler.

name string (required)

Tenant/script name (a-zA-Z0-9_-).

response object (required)

JSON object returned on KV dispatch. Max serialized size: 10,000 bytes.

Example Request

curl -X POST "https://your-worker.workers.dev/scripts" \
  -H "Content-Type: application/json" \
  -d '{"name":"tenant-a","response":{"hello":"world"}}'

GET /scripts

name string (required)

Returns { name, updatedAt, hasResponse }.

Example Request

curl "https://your-worker.workers.dev/scripts?name=tenant-a"

POST /dispatch/:name

  • If DISPATCHER is bound: forwards the request to env.DISPATCHER.get(name).fetch(request).
  • If DISPATCHER.get throws: { error, code: "DISPATCH_ERROR" } (502).
  • Without DISPATCHER (or when using the KV path): returns the stored KV response object.

Example Request

curl -X POST "https://your-worker.workers.dev/dispatch/tenant-a"

POST /register

Record a customer name in KV for listing.

name string (required)

Example Request

curl -X POST "https://your-worker.workers.dev/register" \
  -H "Content-Type: application/json" \
  -d '{"name":"tenant-a"}'

GET /customers

Returns { customers: string[] }.

Example Request

curl "https://your-worker.workers.dev/customers"

Error Codes

  • 400 - Invalid name, response, body, or oversized script (INVALID_NAME, INVALID_RESPONSE, INVALID_BODY, SCRIPT_TOO_LARGE)
  • 404 - Script not found (NOT_FOUND)
  • 502 - Dispatch namespace failure (DISPATCH_ERROR)

Use Cases

  • Learn Workers for Platforms dispatch namespace patterns
  • Prototype multi-tenant routing with a KV fallback
  • Register and list customers before wiring real scripts
  • Teach safe demos that avoid eval while showing dispatch shape

Limitations

  • KV path returns a stored JSON object - no dynamic JS execution
  • Dispatch namespace (demo-customers) may require Workers for Platforms
  • Script payload capped at 10,000 bytes
  • No authentication on register/dispatch endpoints

Use in your project

Copy these files into an existing Worker. Prefer Deployment to try the full experiment first. Source: apps/experiments/user-script-dispatcher.

DependenciesNoneBindingsKVPlatformWorkers runtime
import {  CUSTOMER_KEY_PREFIX,  MAX_NAME_LENGTH,  MAX_SCRIPT_BYTES,  NAME_PATTERN,  SCRIPT_KEY_PREFIX,} from "../constants/defaults";import type { ScriptRecord } from "../types/script";export function validateName(input: string | undefined): string | null {  if (!input || typeof input !== "string") return null;  const trimmed = input.trim();  if (!trimmed || trimmed.length > MAX_NAME_LENGTH) return null;  if (!NAME_PATTERN.test(trimmed)) return null;  return trimmed;}export function validateResponse(input: unknown): Record<string, unknown> | null {  if (!input || typeof input !== "object" || Array.isArray(input)) return null;  return input as Record<string, unknown>;}export function scriptKey(name: string): string {  return `${SCRIPT_KEY_PREFIX}${name}`;}export function customerKey(name: string): string {  return `${CUSTOMER_KEY_PREFIX}${name}`;}export function serializeScript(name: string, response: Record<string, unknown>): string | null {  const record: ScriptRecord = {    name,    response,    updatedAt: new Date().toISOString(),  };  const raw = JSON.stringify(record);  if (raw.length > MAX_SCRIPT_BYTES) return null;  return raw;}export function parseScriptRecord(raw: string): ScriptRecord | null {  try {    const parsed = JSON.parse(raw) as Partial<ScriptRecord>;    if (!parsed.name || typeof parsed.name !== "string") return null;    if (!parsed.response || typeof parsed.response !== "object") return null;    return {      name: parsed.name,      response: parsed.response as Record<string, unknown>,      updatedAt: parsed.updatedAt ?? new Date(0).toISOString(),    };  } catch {    return null;  }}export async function saveScript(  kv: KVNamespace,  name: string,  response: Record<string, unknown>): Promise<ScriptRecord | null> {  const raw = serializeScript(name, response);  if (!raw) return null;  const record = parseScriptRecord(raw);  if (!record) return null;  await kv.put(scriptKey(name), raw);  return record;}export async function getScript(kv: KVNamespace, name: string): Promise<ScriptRecord | null> {  const raw = await kv.get(scriptKey(name));  if (!raw) return null;  return parseScriptRecord(raw);}export async function registerCustomer(kv: KVNamespace, name: string): Promise<void> {  await kv.put(customerKey(name), JSON.stringify({ name, registeredAt: new Date().toISOString() }));}export async function listCustomers(kv: KVNamespace): Promise<string[]> {  const listed = await kv.list({ prefix: CUSTOMER_KEY_PREFIX });  return listed.keys    .map((k) => k.name.slice(CUSTOMER_KEY_PREFIX.length))    .filter(Boolean)    .sort();}

Deployment

Click the deploy button

Deploy to Cloudflare Workers

Configure KV and dispatch namespace

Create a KV namespace bound as SCRIPTS. For production dispatch, create a dispatch namespace matching demo-customers in wrangler.json. Local/KV fallback works without the paid feature.

Test your deployment

curl -X POST "https://your-worker.workers.dev/scripts" \
  -H "Content-Type: application/json" \
  -d '{"name":"tenant-a","response":{"hello":"world"}}'
curl -X POST "https://your-worker.workers.dev/dispatch/tenant-a"

Local Development

cd apps/experiments/user-script-dispatcher
npm install
npm run dev
curl -X POST "http://localhost:8787/scripts" \
  -H "Content-Type: application/json" \
  -d '{"name":"tenant-a","response":{"hello":"world"}}'
curl -X POST "http://localhost:8787/dispatch/tenant-a"

Configuration

wrangler.json declares:

  • KV namespace SCRIPTS
  • Dispatch namespace DISPATCHER → demo-customers

Cloudflare Features Used

On this page