Edge Workers overview and quickstart
Create a Worker, write code, bind it to domain routes, and learn the API, route matching rules and resource limits.
Edge Workers are JavaScript functions that run on CDN edge nodes. When a request reaches the edge and passes security checks, a Worker whose route matches runs before the cache lookup and before the request goes to your origin. A Worker can:
- Respond directly: return custom content or a redirect, without contacting the origin.
- Rewrite the origin request: add or overwrite request headers (and optionally change the method and path), then continue to the origin.
- Pass through: change nothing, so the request is handled by the domain's normal configuration.
The programming model follows Cloudflare Workers: export export default { fetch(request, env, ctx) } and return a Response. Every execution runs in a fresh, isolated sandbox. No global state is shared between requests.
Console pages
The console menus are in Chinese; English translations are given in parentheses.
| Page | Location | Purpose |
|---|---|---|
| Workers list | Sidebar CDN管理 (CDN) → Workers (/cdn/workers) | View, create, enable/disable and delete Workers |
| Worker editor | Click 详情 (Details) in the list (/cdn/workers/<ID>) | Edit name, description and code; see the version number |
| Domain Worker bindings | CDN管理 → 域名管理 (Domains) → open a domain → Worker tab (/cdn/domains/<domain>/worker) | Bind Workers to route patterns on that domain |
Quickstart
Step 1: Create a Worker
- Go to CDN管理 → Workers and click 创建Worker (Create Worker) in the top-right corner.
- Enter a 名称 (Name), which is required, and an optional 描述 (Description).
- You can pick a sample from the 从模板开始 (Start from a template) drop-down to load it into the editor. Samples include custom response, redirect, auth token, crypto toolbox and fetch passthrough. Or paste the example below.
- Make sure the 启用 (Enabled) switch is on, then click 保存更改 (Save).
After saving, the editor opens the Worker's detail page with its version number at the top. The version goes up by one each time you save new code.
Step 2: Write the code
This minimal example returns JSON from the edge for /hello. Every other path goes to the origin as usual.
export default {
async fetch(request, env, ctx) {
// request.url may be "/hello?x=1" or a full URL, so extract the path
const path = request.url.replace(/^https?:\/\/[^\/]+/, "").split("?")[0];
if (path === "/hello") {
return Response.json({
message: "Hello from the edge",
host: request.headers.get("host"),
method: request.method,
});
}
// Not handled here: pass through to the origin
return { action: "continue" };
},
};Step 3: Bind it to a domain
- Go to CDN管理 → 域名管理, open the domain and switch to the Worker tab.
- Click 添加绑定 (Add binding). In the dialog:
- 选择Worker (Worker): choose the Worker you just created. Only enabled Workers are listed.
- 路由模式 (Route pattern): for example
/hello, or/*for all paths. The rules are explained below. - 优先级 (Priority): 0–999. Higher numbers win.
- 启用 (Enabled): leave it on.
- Click 保存 (Save). The configuration is pushed to the edge automatically and normally takes effect shortly.
Step 4: Test
curl -i https://www.example.com/helloA 200 with the JSON above means the Worker is live. Other paths should behave exactly as they did before you added the binding.
Programming interface
Entry point
The recommended form is export default { fetch(request, env, ctx) { ... } }. fetch can be a regular or an async function. The platform also accepts export default function (request) {} and a global function handler(request) {}.
The request object
| Member | Description |
|---|---|
request.method | Request method, e.g. GET |
request.url | The request target. It may be only the path and query string (e.g. /a?b=1) or a full URL, so extract the path as in the example |
request.headers.get(name) | Read a request header. Names are case-insensitive. Returns null if absent. has() is also available |
Workers cannot currently read the request body. request.text() and request.json() return empty content at the edge. Do not rely on the body.
Return values
| Return | Effect |
|---|---|
new Response(body, { status, headers }) | Sent to the client as-is; the origin is not contacted |
Response.json(data, init) | JSON response with content-type: application/json set automatically |
Response.redirect(url, status) | Redirect, 302 by default |
{ action: "continue" } or no return value | Pass through unchanged |
{ action: "rewrite", headers: {...} } | Add or overwrite these headers on the origin request, then continue. You can also pass method and url (new path and query string) |
For example, this Worker tags origin requests with an A/B bucket:
export default {
fetch(request) {
const cookie = request.headers.get("cookie") || "";
const m = /ab_bucket=(A|B)/.exec(cookie);
const bucket = m ? m[1] : (Math.random() < 0.5 ? "A" : "B");
return { action: "rewrite", headers: { "x-ab-bucket": bucket } };
},
};rewrite can only add or overwrite request headers. It cannot remove them. If you include headers with { action: "continue" }, they are ignored. Use rewrite to change headers.
Available globals
fetch(url, init): makes a subrequest to a public HTTP/HTTPS address and returnsPromise<Response>withstatus,ok,headers,text()andjson(). You canreturn fetch(url)to send the result straight to the client.Headers,Request,Response,TextEncoder/TextDecoder,btoa/atob.crypto.subtle.digest,crypto.subtle.importKey/sign/verify(HMAC),crypto.getRandomValues,crypto.randomUUID, and the helperscrypto.md5(),crypto.sha1(),crypto.sha256()andcrypto.hmac(), which return hex strings.
Subrequest restrictions:
- Only
http/httpsto ports 80 and 443. - Private, loopback and link-local addresses are always refused.
- At most 3 redirects are followed. Each subrequest times out after 10 seconds, and response bodies are capped at 8 MiB.
Bodies are handled as text. Workers suit text, HTML and JSON. They are not suitable for generating or proxying binary content such as images.
Route patterns
A route pattern is matched against the request path only, without the hostname or query string. It must match the whole path.
*matches any sequence of characters, including/, so it spans multiple directory levels.**behaves the same as*.?matches a single character.- An empty pattern,
*or/*matches every path.
| Pattern | Matches | Does not match |
|---|---|---|
/hello | /hello | /hello/, /hello/a |
/api/* | /api/, /api/users, /api/users/123 | /api |
/*.json | /data.json, /a/b/c.json | /data.json5 |
At most one Worker runs per request. If several bindings match, only the one with the highest priority runs. Give overlapping bindings different priorities.
Resource limits
| Item | Limit |
|---|---|
| Code size | 3 MB (larger code fails to save) |
| Compute time per execution | 5 seconds (time spent waiting on fetch is not counted) |
Total fetch wait time per execution | 15 seconds |
| Memory | Design to stay within 10 MB |
| Subrequests | Design for at most 10 per execution |
| Stack size | 256 KB |
| Response returned by a Worker | 8 MiB |
Errors and debugging
When a Worker throws, has a syntax error, times out or exceeds a limit, the platform fails open. The request continues to the origin as if no Worker were bound, and no error page is shown. If you don't get the result you expect, first check that your code runs correctly.
console.log() output is not currently collected anywhere, and there is no online debugger. While developing, wrap your logic in try { ... } catch (e) { return new Response(String(e), { status: 500 }); } so errors show up in the response. Test with curl, then remove the wrapper.
Enabling, disabling and deleting
- When you 禁用 (Disable) a Worker in the Workers list, it stops running on every domain. You can also disable a single binding on a domain's Worker tab.
- Deleting a Worker stops it on every domain it was bound to.
- When you save new code, every domain bound to that Worker is updated automatically.
Plans and quotas
The number of Worker routes (bindings) per domain depends on the CDN plan linked to that domain. At the time of writing, the CDN Starter, Professional and Enterprise plans each allow 5 per domain. See the Plans page for current values. When you reach the limit, the console shows a "Worker route limit reached" notice (in Chinese: 已达 Worker 路由上限). To add more, upgrade your plan or delete existing bindings.
Managing Workers via the API
Every console action maps to a user API call. Authenticate with your login token in an Authorization: Bearer <token> header:
# Create a Worker (include an "id" field to update an existing one)
curl -X POST https://api.yeap.cloud/api/user/cdn/workers/save \
-H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
-d '{"name":"hello","code":"export default { fetch(){ return new Response(\"hi\"); } };","enabled":true}'
# Bind it to a domain
curl -X POST https://api.yeap.cloud/api/user/cdn/domains/www.example.com/workers/save \
-H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
-d '{"worker_id":123,"route_pattern":"/hello","priority":10,"enabled":true}'Other endpoints:
- Workers:
GET /api/user/cdn/workers(list),GET /api/user/cdn/workers/detail?id=(details, including code),POST /api/user/cdn/workers/toggle, andDELETE /api/user/cdn/workers/delete(JSON body{"id":...}). - Domain bindings:
GET /api/user/cdn/domains/<domain>/workers,POST .../workers/toggleandDELETE .../workers/delete.
Not currently supported
- Reading the request body.
- Setting environment variables or KV for a Worker in the console (
envis an empty object). - Modifying the response returned by your origin. The "response header rewrite" template does not currently take effect. To add response headers, use the domain's rules feature.
- Background work passed to
ctx.waitUntil(), which is not guaranteed to run after the response is sent. - Execution logs and online debugging.