Setting up bulk redirect rules in Cloudflare is not about creating a static list of old URLs to new URLs; it’s about defining patterns that Cloudflare’s edge can dynamically translate.

Let’s see it in action. Imagine you’ve migrated your entire blog from /blog/post-title/ to /articles/post-title/. Instead of manually creating thousands of individual redirect rules, you can define a single pattern.

Here’s a simplified wrangler.toml snippet for a Cloudflare Worker that handles this:

name = "redirect-worker"
main = "src/index.ts"

[[routes]]
pattern = "/blog/*"
custom_domain = "yourdomain.com"

And the corresponding src/index.ts worker code:

export default {
  async fetch(request: Request): Promise<Response> {
    const url = new URL(request.url);

    if (url.pathname.startsWith('/blog/')) {
      const newPath = url.pathname.replace('/blog/', '/articles/');
      return Response.redirect(new URL(newPath, url.origin).toString(), 301);
    }

    // Fallback to origin for all other requests
    return fetch(request);
  },
};

When a request comes in for https://yourdomain.com/blog/my-first-post/, the worker intercepts it. It sees the /blog/ prefix, strips it off, prepends /articles/, and returns a 301 Moved Permanently redirect to https://yourdomain.com/articles/my-first-post/. The fetch(request) at the end is crucial; it ensures that any URLs not matching your redirect pattern are still served by your origin server.

The problem this solves is efficiently managing URL changes during site migrations or restructuring. Without bulk redirects, you’d be creating hundreds or thousands of individual rules, which is tedious, error-prone, and inefficient for your origin server to process. Cloudflare’s edge handles this pattern matching, meaning the redirect decision is made without ever hitting your origin for the old URL.

The core mechanism here is pattern matching and dynamic URL construction. The url.pathname.startsWith('/blog/') checks if the incoming path matches the old pattern. url.pathname.replace('/blog/', '/articles/') is the transformation logic. Response.redirect(..., 301) sends the HTTP status code that tells browsers and search engines this is a permanent move.

You can get much more sophisticated. For example, preserving query parameters is essential. If someone links to https://yourdomain.com/blog/old-page/?utm_source=newsletter, you want them to end up at https://yourdomain.com/articles/old-page/?utm_source=newsletter. The request.url already contains the full URL with query parameters, and new URL(newPath, url.origin).toString() correctly reconstructs the target URL, including any existing query parameters.

Another common scenario is redirecting a root domain to a subdomain, or vice-versa. For instance, redirecting yourdomain.com/some-page to www.yourdomain.com/some-page. Your worker could look like this:

export default {
  async fetch(request: Request): Promise<Response> {
    const url = new URL(request.url);

    // Redirect root domain to www
    if (url.hostname === 'yourdomain.com') {
      const newUrl = new URL(`https://www.yourdomain.com${url.pathname}${url.search}`);
      return Response.redirect(newUrl.toString(), 301);
    }

    // Handle other specific redirects or pass through
    if (url.pathname.startsWith('/blog/')) {
      const newPath = url.pathname.replace('/blog/', '/articles/');
      return Response.redirect(new URL(newPath, url.origin).toString(), 301);
    }

    return fetch(request);
  },
};

In this example, url.hostname === 'yourdomain.com' checks the domain. new URL(https://www.yourdomain.com${url.pathname}${url.search}) constructs the new URL, ensuring the www. subdomain is added while preserving the original path and any query strings.

A subtle but powerful aspect of Cloudflare Workers for redirects is their ability to execute JavaScript at the edge. This means complex, conditional logic can be applied to redirects without impacting your origin server’s performance. You can check user agents, A/B test redirect destinations, or even integrate with external data sources to determine the correct redirect target, all before the request even reaches your origin. This level of dynamic control is what differentiates it from static redirect maps.

The next step in managing site migrations with Cloudflare would be to explore Cloudflare’s built-in Redirect Rules feature, which offers a UI-driven way to achieve many of these patterns without writing custom JavaScript.

Want structured learning?

Take the full Cloudflare course →