I Installed drupal/redirect for Four URLs. It Redirected Every Node Path on the Site.

I had exactly four URLs I wanted redirected. Two articles had accidentally been published twice in July under different titles — a mixup during the early days of the JSON:API publishing pipeline — and once I'd settled on which copy of each to keep, the other needed to 301 somewhere instead of just disappearing. Four source paths, four targets, done. That's a job for drupal/redirect, so I added it: "drupal/redirect": "^1.13" in composer.json, pulling in version 1.13.0 from drupal.org.

Creating the actual rules was a two-minute job with drush, one per stale URL:

  • publishing-drupal-jsonapi-config-managed-rest-pipeline -> internal:/node/164 (301)
  • node/137 -> internal:/node/164 (301)
  • email-self-hosting-2026-it-still-possible-without-getting-blacklisted-0 -> internal:/node/136 (301)
  • node/185 -> internal:/node/136 (301)

Four rows in the redirect table, four dead URLs pointed at the article that was actually staying. I didn't think about the module again until a completely unrelated request — /node/164 itself, the canonical node path of the article I'd just consolidated everything onto — also came back a 301.

That's not one of the four rules I wrote. Nothing sends /node/164 anywhere in that list.

The setting nobody asked to be installed

The module's own config, imported the moment I enabled it, is sitting right there in sync/redirect.settings.yml:

  • auto_redirect: true
  • route_normalizer_enabled: true

Route normalization is a real, documented feature of the redirect module, not a bug: with it on, any request that resolves to a node's internal path gets 301'd to that node's actual alias, for every node on the site, unconditionally. I'd read "redirect module" as "a table of redirect rules I control." It's that, plus a sitewide policy decision — every bare /node/X request becomes canonical-redirect territory the moment the module is enabled with its own defaults, whether or not that node has ever appeared in my four-row table.

I checked this directly rather than taking the settings file's word for it:

curl -sk -o /dev/null -w "%{http_code} %{redirect_url}" https://linkhub.ddev.site/node/164

301, redirecting to the article's real alias. Every other node on the site behaves the same way — I spot-checked a handful of others and got the identical pattern, alias every time, none of them in my redirect table.

Why this is actually the right default, once you see the reasoning

Once I stopped being annoyed and thought about why the module ships this way, it's hard to argue with. This site already runs Pathauto, so every node has a canonical alias. A crawler or an old inbound link that hits the bare /node/164 form instead of the alias is exactly the kind of duplicate-URL situation the whole redirect module exists to clean up — the same category of problem as the four rows I set out to fix, just handled automatically instead of one entry at a time. Turning that off and relying purely on hand-written rules would mean re-discovering and re-fixing this same pattern, one URL at a time, forever, instead of getting it handled for the entire site the moment Pathauto and Redirect are both active.

The part worth remembering isn't "route normalization is good" or "route normalization is bad." It's that I installed a module to solve a four-row problem and got a sitewide policy along with it, and the only reason I know that is because I happened to request the one path where the two behaviors collided. If /node/164 had never been requested directly after the cleanup, this setting could have sat there unexamined indefinitely, doing something I hadn't consciously decided on.

What I actually checked before leaving it alone

I left route_normalizer_enabled on. It's redundant with Pathauto's own aliasing in the common case — a bare node path is already unusual traffic on this site — but redundant-and-harmless is a fine place to land, and turning it off would mean the four-row table is doing double duty covering cases the module would otherwise catch for free. What I did change is how I read a new module's settings file before deploying it: composer require tells you what code you added; the config it installs alongside itself tells you what behavior you actually turned on, and those are not the same question. A four-URL problem and a sitewide redirect policy can arrive in the same commit, and only one of them was the thing I asked for.

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.
Please share this article on your favorite website or platform.