Configure redirects

Learn how to configure redirects in Fern Docs. Set up exact path redirects and regex patterns to preserve SEO equity when pages move.

View as Markdown

Redirects map old URLs to new ones so inbound links and search rankings survive when pages move, change slugs, or are deleted. They apply to Markdown URLs too: a redirected page’s .md or .mdx twin returns a 308 to the destination’s twin.

Set up redirects

Configure redirects in docs.yml, pointing at either internal paths or external URLs. Use an exact path when a single URL moves, and a pattern when a path’s descendants move with it: an exact source matches that one URL and nothing beneath it, so /old-folder leaves /old-folder/page alone.

If your docs are hosted on a subpath (like buildwithfern.com/learn), include the subpath in both the source and destination paths.

docs.yml
1redirects:
2 # Exact path redirects
3 - source: "/old-path"
4 destination: "/new-path"
5 - source: "/old-folder/path"
6 destination: "/new-folder/path"
7 - source: "/old-folder/path"
8 destination: "https://www.example.com/fern" # External destination
9 - source: "/temporary-redirect"
10 destination: "/new-location"
11 permanent: false # Use 307 (temporary) instead of 308 (permanent)
12
13 # Pattern-based redirects
14 - source: "/old-folder/:slug" # Matches single segments: /old-folder/foo
15 destination: "/new-folder/:slug"
16 - source: "/old-folder/:slug*" # Matches multiple segments: /old-folder/foo/bar/baz
17 destination: "/new-folder/:slug*"
18 - source: "/old-:slug(.*)" # Matches mid-segment: /old-guides/setup
19 destination: "/new-:slug(.*)"

Pattern syntax

A parameter is a name prefixed with :. Each one captures part of the incoming URL and is replayed in destination under the same name.

PatternExample sourceMatches
:slug/plants/:slug/plants/monstera, not /plants/indoor/monstera
:slug*/plants/:slug*/plants and /plants/indoor/monstera
:slug+/plants/:slug+/plants/indoor/monstera, not /plants
:slug(regex)/plants-:slug(.*)/plants-indoor/monstera
(regex)/plants/(\d+)/plants/42

An unnamed group has no name to replay, so it appears in destination as :0.

A regular expression is the only way to match mid-segment, because :slug, :slug*, and :slug+ all have to follow a /. It also narrows a parameter rather than widening one: /v:version(\d+)/plants/:slug* matches /v2/plants/monstera/care and captures version as 2.

Repeat the regular expression in destination. A parameter written as :slug(.*) in source stays :slug(.*) in destination, because a bare :slug can’t hold a value containing /; omitting it resolves the redirect to the literal text /new-folder/:slug.

The optional modifier (?) is unsupported. Fern strips each source at the first ? to remove search parameters, so /old-folder/:slug? is matched as /old-folder/:slug.

Evaluation order

Redirects are evaluated top-to-bottom and the first match wins, so list specific paths before broader ones:

docs.yml
1redirects:
2 # Specific path first — matches /docs/api/billing/overview, etc.
3 - source: "/docs/api/billing/:slug*"
4 destination: "/docs/reference/billing/:slug*"
5
6 # Broader catch-all second — matches everything else under /docs/api/
7 - source: "/docs/api/:slug*"
8 destination: "/docs/reference/:slug*"

Properties

Each entry under redirects accepts the following properties.

source
stringRequired

The relative path you want to redirect from (e.g., /old-path). Must be a relative path, not an absolute URL. Must not include search parameters (e.g., ?key=value). Trailing slashes are normalized before matching, so /old-path/ and /old-path are equivalent. Match the casing of the URL you’re redirecting from.

destination
stringRequired

The path you want to route to. Can be an internal path (/new-path) or an external URL (https://example.com). External URLs must include the full address, including https.

permanent
booleanDefaults to true

By default, uses the 308 status code to instructs clients and search engines to cache the redirect forever. Set to false only if you need a temporary redirect using the 307 status code, which won’t be cached.

When not to add a redirect

For optimal site performance, only add redirects when necessary. Fern already handles 404s and version routing, and redirects that duplicate those behaviors work against them.

404 handling

Don’t redirect broken links to your homepage:

docs.yml
1redirects:
2 - source: /docs/event-notifications
3 destination: / # Don't do this

Instead, enable automatic homepage redirects in your docs.yml to send broken links to your homepage rather than showing a 404 page:

docs.yml
1settings:
2 hide-404-page: true

Versioning

If you have versions configured, your default version uses unversioned paths (/docs/getting-started), while other versions use versioned paths (/docs/v2/getting-started). Fern automatically handles version routing by redirecting broken versioned links to the default version and managing canonical URLs.

Avoid redirecting from unversioned to versioned URLs:

docs.yml
1redirects:
2 - source: /docs/event-notifications
3 destination: /docs/v2/event-notifications # Don't do this

Overriding the default versioning behavior manually can lead to unexpected redirect patterns. If you frequently need to redirect from the default version to another version, change which version is set as default in your versions configuration.

Catching missing redirects

The missing-redirects rule, run by fern check, compares the navigation tree built from your local YAML against the most recently published state of your site and flags previously published URLs that no longer resolve and aren’t covered by an entry in redirects:. This catches pages you’ve moved or removed before they start returning 404s for existing inbound links. Tune its severity in docs.yml.