Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 84 additions & 92 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,106 +1,98 @@
# Workers for Platforms Example Project

- [Blog post](https://blog.cloudflare.com/workers-for-platforms/)
- [Docs](https://developers.cloudflare.com/cloudflare-for-platforms/workers-for-platforms)
- [Discord](https://discord.cloudflare.com/)

This is a **minimal Workers for Platforms** example that demonstrates the core concepts of dynamic dispatch. The platform allows users to create and upload custom Workers through a simple web interface, then access them via friendly URLs.

Workers for Platforms gives your customers the ability to build services and customizations (powered by Workers) while you retain full control over how their code is executed and billed. The **dynamic dispatch namespaces** feature makes this possible.

By creating a dispatch namespace and using the `dispatch_namespaces` binding in a regular fetch handler, you have a "dispatch Worker":

```javascript
export default {
async fetch(request, env) {
// "dispatcher" is a binding defined in wrangler.jsonc
// "my-user-worker" is a script previously uploaded to the dispatch namespace
const worker = env.dispatcher.get("my-user-worker");
return await worker.fetch(request);
Here are the full operational details, complete configuration files, and step-by-step commands for setting up your Workers for Platforms dynamic dispatch application.
1. Configuration Manifest (wrangler.jsonc)
Save this file in your root directory to link your dispatch namespace and KV mappings:
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "workers-for-platforms-example-project",
"main": "src/index.ts",
"compatibility_date": "2026-03-01",

// Dynamic Dispatch Namespace Binding for User Workers
"dispatch_namespaces": [
{
"binding": "dispatcher",
"namespace": "workers-for-platforms-example-project",
"remote": true
}
],

// KV storage mapping friendly names to user script IDs
"kv_namespaces": [
{
"binding": "WORKER_MAPPINGS",
"id": "REPLACE_WITH_KV_ID",
"preview_id": "REPLACE_WITH_PREVIEW_KV_ID"
}
],

"vars": {
"DISPATCH_NAMESPACE_NAME": "workers-for-platforms-example-project"
}
}
```

This is the perfect way for a platform to create boilerplate functions, handle routing to "user Workers", and sanitize responses. You can manage thousands of Workers with a single Cloudflare Workers account!

## In this example

Users can upload Workers scripts through a simple web form. The platform uploads the script to a dispatch namespace and stores a name → Worker ID mapping in Workers KV. Users can then access their Workers via URLs like `/user-workers/my-worker`.

This minimal example focuses on the core Workers for Platforms concepts:
- Dynamic dispatch using the `dispatcher` binding
- Worker upload via the Cloudflare API
- Simple name-based routing using KV storage

## Key Features

- **Simple Worker Creation**: Web form for uploading Worker code
- **Dynamic Dispatch**: Route requests to user Workers by name
- **KV Storage**: Store friendly name mappings
- **No Dependencies**: Pure Workers runtime with minimal external dependencies

## Getting started

Your Cloudflare account needs access to Workers for Platforms.

1. Install the package and dependencies:
2. Core Dispatch Script (src/index.ts)
This entry-point script handles incoming requests, checks the KV mapping for the requested worker name, and routes execution dynamically to the target user worker:
export interface Env {
dispatcher: DispatchNamespace;
WORKER_MAPPINGS: KVNamespace;
DISPATCH_NAMESPACE_NAME: string;
}

```
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const url = new URL(request.url);
const pathParts = url.pathname.split("/");

// Example route pattern: /user-workers/{worker-name}
if (pathParts[1] === "user-workers" && pathParts[2]) {
const workerFriendlyName = pathParts[2];

try {
// 1. Look up the actual internal script name/ID from KV
const scriptName = await env.WORKER_MAPPINGS.get(workerFriendlyName);
if (!scriptName) {
return new Response(`Worker "${workerFriendlyName}" not found in mappings.`, { status: 404 });
}

// 2. Fetch the user worker dynamically from the dispatch namespace binding
const userWorker = env.dispatcher.get(scriptName);

// 3. Rewrite request path if needed and proxy execution
const modifiedRequest = new Request(request);
return await userWorker.fetch(modifiedRequest);

} catch (error: any) {
return new Response(`Error dispatching worker: ${error.message}`, { status: 500 });
}
}

return new Response("Workers for Platforms Gateway Active. Use /user-workers/{name}", {
status: 200,
headers: { "Content-Type": "text/plain" }
});
},
};

3. Setup & Deployment Command Sequence
Execute these steps in your terminal to initialize and provision your platform infrastructure:
* Install Dependencies:
npm install
```

2. Create an API token with Workers Scripts (Edit) permission:

Visit [https://dash.cloudflare.com/?to=/:account/api-tokens](https://dash.cloudflare.com/?to=/:account/api-tokens) and create a new token with the "Workers Scripts (Edit)" permission.

3. Copy the `.env.test` file to `.env` and set the `CLOUDFLARE_API_TOKEN` and `CLOUDFLARE_ACCOUNT_ID` secrets:

```sh
cp .env.test .env
```

Then edit the `.env` file with your actual values:

```sh
CLOUDFLARE_ACCOUNT_ID = "your_actual_account_id"
CLOUDFLARE_API_TOKEN = "your_actual_api_token"
```

The `.env` file is already in `.gitignore` and will not be committed to git.

Then run the following commands to add these secrets to your Worker in production:

```
* Authenticate & Set API Secrets:
npx wrangler secret put CLOUDFLARE_API_TOKEN
```

```
npx wrangler secret put CLOUDFLARE_ACCOUNT_ID
```
npx wrangler secret put CLOUDFLARE_ACCOUNT_ID

4. Create a KV namespace for Worker mappings:

```
* Create the KV Namespace for Mappings:
npx wrangler kv:namespace create "WORKER_MAPPINGS"
```

Copy the namespace ID and preview ID into `wrangler.jsonc` under the `kv_namespaces` binding.

5. Create a dispatch namespace:

```
(Copy the generated ID and update it in your wrangler.jsonc file).
* Create the Dispatch Namespace:
npx wrangler dispatch-namespace create workers-for-platforms-example-project
```

6. Run the Worker in dev mode:
```
npm run dev
```
Or deploy to production:
```
npm run deploy
```
* Run Locally or Deploy:
* Local Emulation:
npm run dev

Once the Worker is live, visit [localhost:8787](http://localhost:8787/) in a browser. You can create a new Worker via the "/upload" link. Access your Workers at `/user-workers/{name}`!
* Production Deployment:
npm run deploy

Then access it at: `http://localhost:8787/user-workers/my-worker`