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
FetchEventlifecycle and request interception boundaries - Configure
wrangler.tomlfor environment-specific route bindings - Implement conditional routing using
URLPattern, headers, andcf.geo - Validate routing behavior with
curl -I,dig, andwrangler taillogs
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 loginand 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
URLPatternorstartsWith()for RFC-compliant routing - Preserve original headers and inject routing metadata via
new Request() - Handle fallback logic to prevent
5xxerrors 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
routesarray inwrangler.tomlfor explicit path matching - Use the
--envflag 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-rayheaders
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 -Ito inspect HTTP status codes and redirect chains - Run
dig yourdomain.comto 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:
5xxerrors, unexpectedcf-cache-status: HITon dynamic paths, high egress costs. - Root Cause: Overlapping string matches or missing fallback logic causing recursive edge fetches.
- Resolution: Implement
cf-cache-status: BYPASSduring testing. Validate redirect chains withcurl -L. PreferURLPatternover 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-rayheaders. - 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.comto 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.