---
title: Redirects · Cloudflare Style Guide
description: As your content changes (and it will change), redirects preserve
  continuity for your users and (friendly) bots.
lastUpdated: 2025-07-16T14:37:31.000Z
chatbotDeprioritize: true
source_url:
  html: https://developers.cloudflare.com/style-guide/how-we-docs/redirects/
  md: https://developers.cloudflare.com/style-guide/how-we-docs/redirects/index.md
---

As your content changes (and it will change), redirects preserve continuity for your users and (friendly) bots.

The most obvious part of this is the user experience. If you click a link in the dashboard or use a bookmarked URL, you trust that it's taking you to the right place. Not a `404` page or the wrong page, but the right page. Redirects help direct users to the right place.

The same applies to the automated experience. If you move a page without redirects, you are losing the historical search authority that Google and other search engines use to rank your page.

***

## How we add redirects

### Cloudflare Workers (primary)

Our primary method takes advantage of [Workers Static Assets](https://developers.cloudflare.com/workers/static-assets/redirects/), defining redirects in a [plain text file](https://github.com/cloudflare/cloudflare-docs/blob/production/public/__redirects) in our GitHub repo.

This setup allows us to use the same workflow for redirects as for any other documentation change. We implement a redirect in the same pull request as the content change and can test these changes in our preview branches. For maintenance, we try to keep these redirects [organized](#organize-your-redirects) by product and then — within each product — organized alphabetically.

We also love the flexibility provided by the [Pages syntax](https://developers.cloudflare.com/workers/static-assets/redirects/#advanced-redirects).

### Bulk redirects (secondary)

In certain situations, we also use [Bulk redirects](https://developers.cloudflare.com/rules/url-forwarding/bulk-redirects/). We use this strategy sparing because having redirects in multiple places increases the cognitive load and potential confusion of making a change.

Normally, bulk redirects only come up when another team is adding a large number of individual redirects to our site, such as when all of our previous `support.cloudflare.com` content was migrated and needed individualized redirects per locale.

We use this method when the contributors are outside of our team and when the total number of redirects is so large that it would clutter our `__redirects` file and count against our [limit for redirects](https://developers.cloudflare.com/workers/static-assets/redirects/#surpass-_redirects-limits).

***

## When we add redirects

Our team adds redirects in two situations: during the course of normal content and as needed based on data.

### During content work

During normal content work, you want to add redirects when you do the following to a page:

* Change any part of the URL (filename, folder).
* Delete the page.

We have some automation to help [flag needed redirects](#potential-redirects).

### Based on data

Another time to add redirects is when you see a lot of `404` response codes on certain paths of your docs site. These `404` responses might be due to a missing redirect or mistyped link.

We identify these status codes either through our [Cloudflare analytics](https://developers.cloudflare.com/analytics/account-and-zone-analytics/zone-analytics/) (ad hoc) or [Logpush job](https://developers.cloudflare.com/logs/logpush/) (more thorough, quarterly).

***

## How we automate redirects

We have two automations in GitHub to help with redirects.

### Infinite redirects

An infinite redirect is when two pages keep redirecting to each other, trapping users in an infitnite loop that will crash their browser.

Because that's just a terrible experience, we explicitly check for that as part of our [required `CI` GitHub action](https://github.com/cloudflare/cloudflare-docs/blob/production/.github/workflows/ci.yml#L62-L63).

We trigger this check *after* we build our site. What it does it then call [`validate-redirects.ts`](https://github.com/cloudflare/cloudflare-docs/blob/production/bin/validate-redirects.ts), which fails on:

* Infinite redirects
* Duplicate redirects
* Redirect targets with anchor links in them

validate-redirects.ts

```ts
import { readFile } from "fs/promises";


async function main() {
  const redirects = await readFile("public/__redirects", { encoding: "utf-8" });


  let numInfiniteRedirects = 0;
  let numUrlsWithFragment = 0;
  let numDuplicateRedirects = 0;


  const redirectSourceUrls: string[] = [];


  for (const line of redirects.split("\n")) {
    if (line.startsWith("#") || line.trim() === "") continue;


    const [from, to] = line.split(" ");


    if (from === to) {
      console.log(`✘ Found infinite redirect:\n    ${from} -> ${to}`);
      numInfiniteRedirects++;
    }


    if (from.includes("#")) {
      console.log(`✘ Found source URL with fragment:\n    ${from}`);
      numUrlsWithFragment++;
    }


    if (redirectSourceUrls.includes(from)) {
      console.log(`✘ Found repeated source URL:\n    ${from}`);
      numDuplicateRedirects++;
    } else {
      redirectSourceUrls.push(from);
    }
  }


  if (numInfiniteRedirects || numUrlsWithFragment || numDuplicateRedirects) {
    console.log("\nDetected errors:");


    if (numInfiniteRedirects > 0) {
      console.log(`- ${numInfiniteRedirects} infinite redirect(s)`);
    }


    if (numUrlsWithFragment > 0) {
      console.log(`- ${numUrlsWithFragment} source URL(s) with a fragment`);
    }


    if (numDuplicateRedirects > 0) {
      console.log(`- ${numDuplicateRedirects} repeated source URL(s)`);
    }


    console.log("\nPlease fix the errors above before merging :)");
    process.exit(1);
  } else {
    console.log("\nDone!");
  }
}


main();
```

### Potential redirects

Contributors often struggle to know when they should add redirects. We try to help them by [adding a comment](https://github.com/cloudflare/cloudflare-docs/blob/production/.github/workflows/potential-redirects-or-partials.yml) to any pull requests that modify or delete content file paths.

![GitHub Actions redirect comment](https://developers.cloudflare.com/_astro/redirects-github.D5I7CV0r_1Xo6uD.webp)

***

## Other guidance

### Organize your redirects

As much as you can, try to organize your redirects into logical groups (products, alphabetical order). This process helps prevent duplicate redirects, as well as identifying specific ones you might be looking for.

In our [`__redirects` file](https://github.com/cloudflare/cloudflare-docs/blob/production/public/__redirects), we use extensive comments, separating different product areas. We also try, as much as we can, to keep the redirects in alphabetical order within a section.

We used to apply a similar principle to [Bulk Redirect lists](https://developers.cloudflare.com/rules/url-forwarding/bulk-redirects/) (when that was our primary method). We created lists that grouped together similar products and labeled them as such, so it was easier to find which redirect you were looking for.

### Know what you can redirect

At the server level, you can trigger a redirect on a URL path (`/page/`), but not a fragment (`/page/#fragment`).

You can redirect a page to a fragment, however (`/page1/` to `/page2/#fragment`).

### Avoid redirect chains

If possible, have all redirects send your users directly to their destination instead of chaining together redirects.

Otherwise, you can have the following situation:

```txt
Page 1 --Redirect-> Page 2 --Redirect-> Page 3 --Redirect-> Page 4
```

Redirect chains are bad because they:

* Slow down the user experience.
* Increase the likelihood of unintentional outcomes (infinite redirects, missing redirects, incorrect redirects).

A way to avoid this outcome is by continually updating the destinations of previous redirects. For example, let's say you changed the name of this page to `/style-guide/how-we-docs/redirect-guidance/`.

In the pull request to update your redirects file, you would want to update the existing redirect as well as adding a new redirect:

```diff
/style-guide/redirects/ /style-guide/how-we-docs/redirects/ 301
/style-guide/redirects/ /style-guide/how-we-docs/redirect-guidance/ 301
/style-guide/how-we-docs/redirects/ /style-guide/how-we-docs/redirect-guidance/ 301
```
