Every few years, someone on a web team opens the redirects file, scrolls through hundreds of rules written by people who no longer work there, and says: "Surely we don't need all of these any more."
Then they delete most of them. And for months afterwards, a slow trickle of 404s arrives from old blog posts, forum threads, printed brochures and bookmarks, each one a link that worked yesterday.
My position is simple: treat your redirects file as append-only. A redirect is a promise to everyone who ever linked to the old URL. Removing it is a breaking change, and it should be as rare and deliberate as removing a public API endpoint.
Why we delete them anyway
The arguments for cleanup sound reasonable:
- "It's been years. Nobody uses those old URLs." You don't know that unless you've checked, and old URLs are exactly the ones in archived articles, old PDFs and printed material you can't update.
- "The file is huge and slow." Sometimes true, and solvable without deleting anything (more on that below).
- "Redirects are bad for SEO." A single permanent redirect is a normal, well-understood signal. What causes trouble is long chains and loops, not the existence of old rules.
- "It's technical debt." It's not debt. It's history, and it's load-bearing.
A URL is an interface
When you publish a URL, you're publishing an interface. People integrate with it in ways you can't see: they link to it, cite it, bookmark it, put it in documentation, print it on packaging, encode it in QR codes, store it in spreadsheets.
We'd never delete a public API endpoint because "it's been years" without checking traffic, announcing a deprecation, and accepting that some clients will break. URLs deserve at least that much care, and in practice they deserve more, because unlike API clients, most people linking to you have no way to hear about your deprecation.
What append-only looks like in practice
Append-only doesn't mean chaotic. It means the rules around the file change:
1. Adding a redirect is easy and routine. Every URL change ships with its redirect in the same pull request. No exceptions, and ideally enforced by a CI check that compares old and new routes.
2. Removing a redirect needs evidence. Before deleting a rule, check your logs: has anyone requested the old URL recently, over a long enough window to include seasonal traffic? Check if any external sites link to it. If both are effectively zero, deletion is defensible. Write down why.
3. Collapse chains, don't remove history. When /a redirects to /b, and later /b redirects to /c, update the first rule to point straight at /c. Both old URLs still work, with a single hop.
# before: a chain
/2019/pricing /pricing-old 301
/pricing-old /pricing 301
# after: flattened, nothing removed
/2019/pricing /pricing 301
/pricing-old /pricing 301
4. Use patterns where they're honest. If a whole section moved, one rule like /blog/:year/:slug -> /articles/:slug replaces hundreds of individual lines, and keeps them all working.
5. Keep the file in version control with context. A comment or commit message explaining why a redirect exists makes the next cleanup conversation much shorter.
A CI check that makes it stick
Policies decay unless something enforces them. A cheap guard: in CI, list every URL your site served on the main branch and every URL in the new build, then fail if any old URL is neither served nor covered by a redirect rule. Most static site generators and frameworks can output a route list or a sitemap, which is enough to diff. It turns "remember to add a redirect" into a failing build, which is much harder to forget.
"But performance"
On most platforms, a few thousand redirect rules are not a real performance concern, especially if exact matches are looked up in a hash map rather than tested one by one. If your platform does evaluate rules linearly and the list is genuinely large, the fix is a better data structure, not fewer promises:
- Move exact-match redirects into a key-value lookup (an edge KV store, a map file, a database table).
- Keep pattern rules few and ordered.
- Measure before and after. Assumed slowness is the most common reason redirects get deleted, and it's rarely measured.
"But they'll accumulate forever"
Yes. That's the point. A website that's been around for ten years has ten years of URLs that people have shared. The redirects file is the map from that past to your present. It grows because your site has a history, and that history is part of why people trust it.
The one exception
If a redirect points somewhere misleading, for example an old product URL redirecting to an unrelated page, it's arguably worse than a 404, because it silently sends readers somewhere they didn't intend to go. Fix those: point them somewhere relevant, or let the old URL return a proper 410 Gone with a helpful page. That's a correction, not a cleanup.
The cost of being wrong
Keeping a redirect nobody needs costs almost nothing: a line in a file. Deleting a redirect somebody needed costs a broken link you'll probably never hear about, in a place you can't fix. Given that asymmetry, the default should be obvious.
We think about this a lot at linkbruno.com, because the most common source of broken inbound links isn't a site disappearing. It's a site that moved, and then forgot where it used to live.
Related reading
- Redirect chains: why 3 hops is 2 too many (and a script that finds them)
- ERR_TOO_MANY_REDIRECTS: the 6 configs that cause redirect loops and how to find them
- Case study (hypothetical): moving from Windows to Linux hosting broke 1,900 links, all because of capital letters
Has your team ever deleted old redirects in a cleanup? What happened next, and would you do it again?
Top comments (0)