Deploying Cloudflare Workers for Dynamic Request Routing

This guide provides production-grade instructions for deploying Cloudflare Workers to intercept, evaluate, and redirect HTTP traffic at the network edge. By leveraging V8 isolates and the Fetch API, DevOps teams can implement conditional routing, path rewriting, and multi-origin failover without origin latency. This architecture sits at the core of modern Edge Routing & Serverless Function Architecture, enabling real-time traffic steering based on headers, cookies, and geolocation data.

Key implementation objectives:

  • Understand the FetchEvent lifecycle and request interception boundaries
  • Configure wrangler.toml for environment-specific route bindings
  • Implement conditional routing using URLPattern, headers, and cf.geo
  • Validate routing behavior with curl -I, dig, and wrangler tail logs

Prerequisites & CLI Environment Setup

Establish the local development environment, authenticate with Cloudflare, and scaffold the Worker project. Ensure your DNS records are proxied (orange cloud enabled). Edge interception fails silently if proxying is disabled.

  • Install Wrangler v3+ via npm or Homebrew
  • Authenticate using wrangler login and verify your Account ID
  • Initialize the project with a JavaScript or TypeScript template
  • Confirm DNS proxy status in the Cloudflare dashboard before proceeding
npm install -g wrangler
wrangler login
wrangler init my-edge-router --type=javascript

Core Routing Logic & FetchEvent Interception

Write the Worker script to parse incoming requests, apply conditional routing rules, and forward traffic to designated origins. This step directly implements the Cloudflare Workers Routing patterns required for production-grade traffic steering.

  • Use export default { async fetch() } for modern module syntax
  • Match paths using URLPattern or startsWith() for RFC-compliant routing
  • Preserve original headers and inject routing metadata via new Request()
  • Handle fallback logic to prevent 5xx errors on unmatched routes
export default {
 async fetch(request, env, ctx) {
 const url = new URL(request.url);
 const routeMap = {
 '/api/v1': 'https://legacy-api.example.com',
 '/api/v2': 'https://modern-api.example.com',
 '/static': 'https://cdn-assets.example.com'
 };
 
 for (const [prefix, origin] of Object.entries(routeMap)) {
 if (url.pathname.startsWith(prefix)) {
 const newUrl = origin + url.pathname.slice(prefix.length) + url.search;
 const newReq = new Request(newUrl, request);
 return fetch(newReq);
 }
 }
 return fetch(request);
 }
};

Execution flow: Iterates through a route map, matches URL prefixes, constructs a new Request object preserving original headers/methods, and fetches from the dynamic origin. Falls back to default origin if no match.

export default {
 async fetch(request, env, ctx) {
 const geo = request.cf?.country;
 let targetOrigin = 'https://us-primary.example.com';
 
 if (geo === 'DE' || geo === 'FR') targetOrigin = 'https://eu-primary.example.com';
 if (geo === 'JP' || geo === 'KR') targetOrigin = 'https://apac-primary.example.com';
 
 const newUrl = targetOrigin + new URL(request.url).pathname + new URL(request.url).search;
 const newReq = new Request(newUrl, request);
 
 try {
 return await fetch(newReq);
 } catch (e) {
 return fetch('https://global-fallback.example.com' + new URL(request.url).pathname, request);
 }
 }
};

Execution flow: Leverages request.cf.country for geographic routing. Implements try/catch for automatic origin failover, ensuring high availability during regional outages.

Deployment & Environment Route Binding

Push routing configurations to staging and production environments while managing environment variables and route patterns. Always deploy to a staging environment first to isolate configuration drift.

  • Define the routes array in wrangler.toml for explicit path matching
  • Use the --env flag for isolated staging/production deployments
  • Bind KV or D1 for dynamic routing tables without triggering full redeployments
  • Verify route propagation via DNS resolution and cf-ray headers

Rollback procedure: If routing breaks post-deploy, immediately revert using wrangler rollback or redeploy the previous successful version via wrangler deploy --name <previous-version-id>.

wrangler deploy --minify --env production
curl -I -s https://yourdomain.com/test-path | grep -E 'cf-ray|server'

Validation & Edge Diagnostics

Verify routing behavior, inspect cache status, and troubleshoot misconfigurations using CLI diagnostics and log streaming. Always validate against production DNS before declaring success.

  • Use curl -I to inspect HTTP status codes and redirect chains
  • Run dig yourdomain.com to verify CNAME/A record proxy status
  • Stream live execution logs with wrangler tail --format pretty
  • Monitor CPU time and memory limits in Cloudflare Analytics
curl -I -s -o /dev/null -w '%{http_code} %{redirect_url}' https://example.com/api/v2
wrangler tail --format pretty

Edge Cases & Warnings

Infinite redirect loops caused by misconfigured path rewriting

  • Symptom: 5xx errors, unexpected cf-cache-status: HIT on dynamic paths, high egress costs.
  • Root Cause: Overlapping string matches or missing fallback logic causing recursive edge fetches.
  • Resolution: Implement cf-cache-status: BYPASS during testing. Validate redirect chains with curl -L. Prefer URLPattern over manual string replacement.

Worker execution timeout exceeding CPU limits (10ms free / 50ms paid)

  • Symptom: 502 Bad Gateway, dropped requests at the edge, latency SLA degradation.
  • Root Cause: Heavy synchronous JSON parsing, complex regex evaluation, or blocking I/O.
  • Resolution: Offload heavy parsing to KV. Use ctx.waitUntil() for async logging. Monitor CPU time in the dashboard and optimize pattern complexity.

DNS proxy disabled (grey cloud) preventing Worker interception

  • Symptom: Routing logic never executes, direct origin IP exposure, missing cf-ray headers.
  • Root Cause: DNS record set to DNS-only mode, bypassing Cloudflare’s reverse proxy layer.
  • Resolution: Verify DNS records show an orange cloud. Run dig yourdomain.com to confirm CNAME resolution to *.workers.dev. Re-enable proxy before deployment.

FAQ

How do I route to different origins based on custom request headers? Parse request.headers.get('X-Target-Origin'), construct a new Request object with the target URL, and return fetch(newRequest). Ensure the header is whitelisted in Cloudflare cache rules if caching is enabled.

Can I bypass Cloudflare cache during dynamic routing? Yes. Set cf: { cacheTtl: 0 } in the fetch options or return a response with Cache-Control: no-cache, no-store, must-revalidate to force edge bypass and trigger an origin fetch.

How do I debug routing failures in production without redeploying? Use wrangler tail --format pretty to stream live logs. Inspect the cf-ray header in curl responses and correlate timestamps with the Cloudflare Logs API for detailed request/response payloads and error traces.