URL Redirects
Restructuring a site retires URLs. Without a redirect the only possible answer at a retired path is a 404, and every indexed link, bookmark and backlink pointing there breaks.
The redirects array declares those retired paths and where each one now lives:
redirects:
- from: /products/platform
to: /
- from: /products/partner
to: /partner
- from: /login
to: /_admin/login
status: 302
Rule Properties
| Property | Description |
|---|---|
from |
Root-relative path to redirect away from. Must start with / and contain no whitespace, ? or #. |
to |
Where to send the visitor — a root-relative path, or an absolute http(s):// URL to hand off to another origin. |
status |
301 (default), 302, 307 or 308. |
Query strings are not part of the match key. An incoming query string is preserved and carried onto the target, so there is no point encoding one in from. If to already carries its own query string, the incoming one is appended to it with &.
Choosing a status
| Status | Meaning | Use it when |
|---|---|---|
301 |
Moved Permanently — transfers link equity | The URL is retired for good. This is the default and the norm. |
302 |
Found — temporary, may rewrite the request method | The move is temporary and the method does not matter. |
307 |
Temporary Redirect — temporary, preserves the method | A temporary move that must keep a POST a POST. |
308 |
Permanent Redirect — permanent, preserves the method | A permanent move that must keep the request method. |
Language Handling
A from is matched the way page paths are authored. A bare rule matches the plain path and every language-prefixed variant, and a path to inherits the language of the request — so one rule serves every locale and a French visitor lands on the French replacement, never the English one:
redirects:
- from: /pricing
to: /plans
That single rule answers /pricing, /en/pricing and /fr/pricing, sending each to /plans, /en/plans and /fr/plans respectively.
To target one locale only, write the language segment into from. A rule whose path already begins with a configured language code is matched literally:
redirects:
- from: /fr/tarifs
to: /fr/plans
An absolute to is used verbatim, with no language handling, since it leaves the app entirely.
Precedence
Redirects are evaluated after static assets and before pages:
- A real file in the public directory — a redirect rule can never hijack a served asset.
- Redirect rules.
- Page resolution.
- The 404 catch-all.
A rule therefore always beats a page. That cuts both ways: a from matching a path you still serve makes that page unreachable.
Redirects resolve in exactly one hop. A matched request emits one redirect and the target is never re-matched against the table, so Location is always literally what you authored. Chains do not collapse — if /a should end at /c, write /a → /c, not /a → /b → /c.
Validation
Three whole-table rules are enforced when the config is decoded, so a broken table fails sovrium validate instead of shipping:
- No duplicate
from— each path may declare at most one rule. - No self-redirect — a rule pointing at its own
fromloops forever. - No cycles —
/a → /btogether with/b → /ais rejected. The server only ever resolves one hop, but the browser follows each new rule in turn and never settles.
Protocol-relative targets (//example.com) are also rejected. A browser resolves them as absolute cross-origin URLs, which would turn the redirect table into an open-redirect primitive; cross-origin hand-offs must spell out https:// so the intent is visible in review.
Collision with a dynamic route is not caught for you. Validation compares from against static page paths only. If your app serves a dynamic route such as /blog/:slug, a rule for /blog/my-post will silently shadow that article — no boot error, no validation failure. Check retired slugs against the content that still exists.
Related Pages
- App Metadata — the other top-level identity properties.
- Pages Overview — the page resolution that redirects run ahead of.
- Languages — the configured language codes that drive prefix matching.
- SEO & Metadata — canonical URLs, which a 301 should agree with.
Last updated July 27, 2026
This documentation was written with AI, so errors or outdated content are possible. Sovrium is in beta — contributions and corrections are welcome.