New usersFree DNS and CDN plans for every new account.Create your account

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.

7 min read Updated Oct 6, 2026

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.

PageLocationPurpose
Workers listSidebar CDN管理 (CDN) → Workers (/cdn/workers)View, create, enable/disable and delete Workers
Worker editorClick 详情 (Details) in the list (/cdn/workers/<ID>)Edit name, description and code; see the version number
Domain Worker bindingsCDN管理 → 域名管理 (Domains) → open a domain → Worker tab (/cdn/domains/<domain>/worker)Bind Workers to route patterns on that domain

Quickstart

Step 1: Create a Worker

  1. Go to CDN管理 → Workers and click 创建Worker (Create Worker) in the top-right corner.
  2. Enter a 名称 (Name), which is required, and an optional 描述 (Description).
  3. 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.
  4. 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.

javascript
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

  1. Go to CDN管理 → 域名管理, open the domain and switch to the Worker tab.
  2. 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.
  3. Click 保存 (Save). The configuration is pushed to the edge automatically and normally takes effect shortly.

Step 4: Test

bash
curl -i https://www.example.com/hello

A 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

MemberDescription
request.methodRequest method, e.g. GET
request.urlThe 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
Warning

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

ReturnEffect
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 valuePass 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:

javascript
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 } };
  },
};
Note

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 returns Promise<Response> with status, ok, headers, text() and json(). You can return 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 helpers crypto.md5(), crypto.sha1(), crypto.sha256() and crypto.hmac(), which return hex strings.

Subrequest restrictions:

  • Only http/https to 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.
Note

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.
PatternMatchesDoes 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

ItemLimit
Code size3 MB (larger code fails to save)
Compute time per execution5 seconds (time spent waiting on fetch is not counted)
Total fetch wait time per execution15 seconds
MemoryDesign to stay within 10 MB
SubrequestsDesign for at most 10 per execution
Stack size256 KB
Response returned by a Worker8 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.

Tip

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:

bash
# 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, and DELETE /api/user/cdn/workers/delete (JSON body {"id":...}).
  • Domain bindings: GET /api/user/cdn/domains/<domain>/workers, POST .../workers/toggle and DELETE .../workers/delete.

Not currently supported

  • Reading the request body.
  • Setting environment variables or KV for a Worker in the console (env is 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.
Was this page helpful?