Cloudflare Workers Routing

Cloudflare Workers Routing enables developers to intercept, inspect, and direct HTTP traffic at the network edge before it reaches origin servers. As a foundational layer of modern Edge Routing & Serverless Function Architecture, it delivers sub-50ms decision-making without provisioning traditional load balancers.

While platforms like Vercel Edge Middleware offer framework-tied routing, Cloudflare’s V8 isolate model operates independently. This allows granular path matching, header injection, and origin failover directly at the CDN level.

Engineers frequently pair this capability with Geo-Targeted Traffic Routing to enforce data residency or serve localized assets. Mastering the configuration lifecycle is critical. Understanding best practices for Deploying Cloudflare Workers for dynamic request routing remains essential for production stability.

Key Routing Principles:

  • Route evaluation follows strict priority: exact matches > prefix matches > wildcard/regex patterns
  • Declarative routing via wrangler.toml or Cloudflare API replaces legacy Page Rules for dynamic logic
  • Workers execute before cache lookup by default, but can run after cache or bypass it entirely
  • Observability relies on structured logging, trace headers, and the Workers Analytics Engine

Route Matching & Priority Architecture

Cloudflare evaluates route patterns sequentially based on declaration order. The first matching pattern triggers the Worker execution. Subsequent matches are ignored to prevent duplicate processing.

Pattern Type Example Priority Execution Behavior
Exact Match example.com/api/v1/status Highest Triggers only on precise path
Prefix Match example.com/api/* High Matches all paths starting with /api/
Wildcard/Regex example.com/docs/* Lowest Evaluated last; supports dynamic segments

Subdomain routing requires explicit zone configuration. Multi-tenant SaaS architectures should isolate tenant routes using path prefixes rather than overlapping subdomains. Route evaluation occurs before Cloudflare’s Always Online and Bot Management layers. Misconfigured overlaps can cause silent route shadowing.

Declarative Configuration with Wrangler

Route definitions are managed via wrangler.toml or the Cloudflare API. The CLI provides immediate validation before edge propagation.

Environment-Specific Route Mapping: Define separate routing tables for staging and production without duplicating code. Environment blocks override base declarations during deployment.

CLI Deployment & Validation:

wrangler routes list --env staging

Expected Output:

ID: abc123
Pattern: staging-api.example.com/*
Script: worker-staging
Zone: example.com

To push updates without triggering full worker redeployments, use wrangler deploy --env production. Always verify route syntax locally with wrangler dev before edge propagation.

Platform Difference: Wrangler CLI enforces strict TOML validation. The Cloudflare Dashboard UI permits overlapping patterns, which can cause unpredictable execution. Always prefer declarative CLI workflows for version control.

Rollback Procedure: If a route causes origin failures, immediately run wrangler routes delete <route-id> or revert the wrangler.toml commit. Cloudflare propagates route removals within 15 seconds globally.

Request Inspection & Path Rewriting

Workers intercept raw HTTP requests. Safe manipulation requires cloning the request object to avoid immutable property errors.

Path Routing & Header Injection:

export default {
 async fetch(request: Request): Promise<Response> {
 const url = new URL(request.url);
 
 if (url.pathname.startsWith('/api/v2')) {
 const newReq = new Request('https://origin-v2.example.com' + url.pathname, request);
 newReq.headers.set('X-Edge-Routed', 'true');
 return fetch(newReq);
 }
 
 return new Response('Not Found', { status: 404 });
 }
};

This pattern strips legacy prefixes, forwards traffic to versioned origins, and injects trace headers. Avoid infinite redirect loops by ensuring rewritten paths do not match the triggering route pattern.

Conditional Routing Headers: Inspect User-Agent, Accept, or custom cookies before forwarding. Normalize headers to prevent cache fragmentation. Always validate header size against Cloudflare’s 8KB limit before forwarding to origin.

Debugging & Observability at the Edge

Production debugging requires real-time log streaming and distributed tracing. Standard console.log() outputs are captured in the Workers runtime.

Live Log Streaming:

wrangler tail --format pretty

Inject cf-ray headers into every response for distributed request tracing. Parse these IDs in your APM to correlate edge decisions with origin latency.

Local Simulation: Run wrangler dev --remote to simulate edge conditions without deploying. This executes your Worker against live Cloudflare infrastructure while routing traffic to your local machine.

Identify route misconfigurations via Cloudflare Logs or the Workers Analytics Engine. Filter by cf-edge-cache status to isolate routing vs caching bottlenecks.

Header Verification via cURL:

curl -I https://api.example.com/v2/status -H "X-Debug: true"

Expected Headers:

cf-ray: 8a1b2c3d4e5f6789-SJC
x-edge-routed: true
cf-cache-status: MISS

Caching & Origin Fallback Strategies

Routing decisions directly impact cache behavior. Workers run before cache lookup by default. You can override this with explicit cache controls.

Cache Control & Failover:

const ROUTE_REGEX = /^\/docs\/([a-z0-9-]+)\/v(\d+)$/;

export default {
 async fetch(request: Request): Promise<Response> {
 const match = new URL(request.url).pathname.match(ROUTE_REGEX);
 if (!match) return fetch(request);
 
 const [, slug, version] = match;
 const originUrl = `https://docs-origin.example.com/${slug}/v${version}`;
 
 try {
 return await fetch(originUrl, { cf: { cacheTtl: 300 } });
 } catch (err) {
 return new Response('Origin Unavailable', { status: 502 });
 }
 }
};

Implement origin failover with try/catch blocks and secondary fetch() calls. Bypass cache for authenticated routes using Cache-Control: no-store. Preserve static asset caching by applying cf: { cacheEverything: true } to public paths.

Use subrequests to warm cache or pre-fetch dynamic content. Verify cache status via the cf-cache-status response header. Expected values: HIT, MISS, EXPIRED, BYPASS.

Configuration Examples

Declarative route mapping in wrangler.toml with environment-specific overrides:

[[routes]]
pattern = "api.example.com/*"
zone_name = "example.com"

[env.production]
[[routes]]
pattern = "api.example.com/v2/*"
zone_name = "example.com"

Defines route patterns that trigger the Worker. Environment blocks allow separate routing tables for staging and production without code duplication.

Path-based routing with origin selection and header injection:

export default {
 async fetch(request: Request): Promise<Response> {
 const url = new URL(request.url);
 
 if (url.pathname.startsWith('/api/v2')) {
 const newReq = new Request('https://origin-v2.example.com' + url.pathname, request);
 newReq.headers.set('X-Edge-Routed', 'true');
 return fetch(newReq);
 }
 
 return new Response('Not Found', { status: 404 });
 }
};

Demonstrates conditional routing based on path prefix. Clones the request to safely modify headers before forwarding to a specific origin server.

Regex route matching with fallback and error handling:

const ROUTE_REGEX = /^\/docs\/([a-z0-9-]+)\/v(\d+)$/;

export default {
 async fetch(request: Request): Promise<Response> {
 const match = new URL(request.url).pathname.match(ROUTE_REGEX);
 if (!match) return fetch(request);
 
 const [, slug, version] = match;
 const originUrl = `https://docs-origin.example.com/${slug}/v${version}`;
 
 try {
 return await fetch(originUrl, { cf: { cacheTtl: 300 } });
 } catch (err) {
 return new Response('Origin Unavailable', { status: 502 });
 }
 }
};

Uses regex to capture dynamic path segments, constructs a new origin URL, applies edge caching, and implements graceful fallback on origin failure.

Edge Cases & Warnings

Scenario Impact Mitigation
Overlapping route patterns in wrangler.toml Unpredictable execution order, duplicate processing, or silent route shadowing Audit route declarations for specificity conflicts; use exact matches where possible and document priority order explicitly
Worker execution exceeding 10ms CPU time limit on free tier Request throttling, 1015 errors, or degraded routing performance Optimize synchronous operations, leverage async fetch() early, and upgrade to Workers Paid for 100ms+ CPU budgets
Routing logic bypassing Cloudflare Cache unintentionally Increased origin load, higher latency, and unexpected CDN egress costs Explicitly set Cache-Control headers, use fetch(request, { cf: { cacheEverything: true } }), and verify cache status via cf-cache-status
Header size limits exceeded during request transformation Truncated headers, dropped cookies, or 431 Request Header Fields Too Large errors from origin Prune unnecessary headers before forwarding, compress payloads, and validate total header size against Cloudflare’s 8KB limit

FAQ

How does Cloudflare determine which route executes when multiple patterns match? Routes are evaluated in declaration order. The first matching pattern triggers the Worker, and subsequent matches are ignored. Exact paths always outrank wildcards and regex.

Can I route traffic to different origins based on request headers? Yes. Workers can inspect headers like Host, User-Agent, or custom auth tokens, then dynamically construct a new Request object pointing to the appropriate origin before calling fetch().

Do Workers routes bypass Cloudflare’s built-in caching? By default, Workers run before cache lookup. You can explicitly bypass, modify, or serve cached responses using the Cache API or fetch() options like cacheEverything and cacheTtl.

How do I debug routing failures in production without impacting live traffic? Use wrangler tail to stream real-time logs, inject cf-ray trace headers, and leverage the Cloudflare Logs dashboard. Test changes in a staging environment with isolated route patterns before promoting to production.