Redirect & Rewrite Rules

To configure redirects and rewrite rules for your Netlify site, add a _redirects file to the root of your published site. You can also add redirect rules to your netlify.toml file.

_Note that if you’re running a build command or site generator, the _redirects file should end up in the folder you’re deploying (the Publish directory in your settings). Some generators, like Jekyll, may also require additional configuration to avoid exclusion of files that begin with the underscore character (_). (For Jekyll, this requires adding an include parameter to _config.yml.)_

Basic redirects

Each redirect rule must be listed on a separate line, with the original path followed by the new path or URL.

# Redirects from what the browser requests to what we serve
/home              /
/blog/my-post.php  /blog/my-post
/news              /blog
/google            https://www.google.com

Any line beginning with # will be ignored as a comment.

The redirects engine will process the first matching rule it finds, reading from top to bottom.

# This rule will trigger at /blog/my-old-title
/blog/my-old-title   /blog/my-new-title

# This rule will never trigger because the previous rule triggers first
/blog/my-old-title   /blog/an-even-better-title

HTTP Status Codes

You can specify the HTTP status code for the rewrite. The default is 301 which will do a permanent redirect.

# Redirect with a 301
/home         /              301

# Redirect with a 302
/my-redirect  /              302

# Rewrite a path
/pass-through /index.html    200

# Show a custom 404 for this path
/ecommerce    /store-closed  404

When the status code is 301, 302, or 303, Netlify will redirect to the target URL. With any other status code Netlify will render the target URL with the specified status code.

This means that in addition to redirects, you can define rewrite rules by specifying 200 as the status code. For more information, check out the Rewrites and Proxying section.

Custom 404

You can set up a custom 404 page for all paths that don’t resolve to a static file. This doesn’t require any redirect rules. Just add a 404.html page to your site and it’ll be picked up automatically.

You can also use this in combination with other features of our redirects by creating explicit entries for different paths:

/en/* /en/404.html 404
/de/* /de/404.html 404

Due to the shadowing behavior in our redirects system, the 404 pages will only be returned for nonexistent assets under the above paths.

Trailing Slash

Our CDN edge nodes do URL normalization before the redirect rules kick in. This happens to make sure we can guarantee the highest possible cache hit rate and the absolute best performance for your site.

What this means for your redirect rules is that Netlify will match paths to rules regardless of whether or not they contain a trailing slash.

# These rules are effectively the same:
# either rule alone would trigger on both paths
/blog/title-with-a-typo    /blog/typo-free-title
/blog/title-with-a-typo/   /blog/typo-free-title

# This rule will cause an infinite redirect
# because the paths are effectively the same
/blog/remove-my-slashes/   /blog/remove-my-slashes  301!

You cannot use a redirect rule to add or remove a trailing slash. However, you can enable Netlify’s Pretty URL feature, from your site dashboard at Settings > Build & deploy > Post processing > Asset optimization.

Check the box for Pretty URLs in the Asset optimization card.

In addition to forwarding paths like /about to /about/ (a common practice in static sites and single page apps), it will also rewrite paths like /about.html to /about/.

Placeholders

You can use placeholders in the origin and target paths:

/news/:year/:month/:date/:slug  /blog/:year/:month/:date/:slug

This would redirect a URL like /news/2004/02/12/my-story to /blog/2004/02/12/my-story

Splats

An asterisk indicates a splat that will match anything that follows:

You can use the splat in your rewrites or redirects like this:

/news/*  /blog/:splat

This would redirect paths like /news/2004/01/10/my-story to /blog/2004/01/10/my-story

The redirect engine processes the first matching rule it finds, so more specific rules should be listed before more general ones:

# This will redirect /jobs/customer-ninja-rockstar
/jobs/customer-ninja-rockstar  /careers/support-engineer

# This will redirect all paths under /jobs except the path above
/jobs/*                        /careers/:splat

# This will never trigger, because the rule above will trigger first
/jobs/outdated-job-link        /careers/position-filled

Query Params

You can also use query parameters in your URL matches.

Note that NO query string parameters are automatically passed on when you redirect a path — you MUST set up rules for every combination as described here, and you have to specify the EXACT set of parameters you are expecting to use this functionality.

The following match will redirect a URL like: /store?id=my-blog-post to /blog/my-blog-post with a 301 redirect.

/store id=:id  /blog/:id  301

Add separate key/value pairs separated by space to match more than one query parameter:

/articles id=:id tag=:tag /posts/:tag/:id 301

If you have multiple parameters, some of which are optional, this is the pattern to follow to ensure that we are prepared to handle all possibilities:

# base case
/path/* /otherpath/:splat 301​

# one value or the other.  Must match exactly!
/path/* param1=:value1 /otherpath/:value1/:splat 301
/path/* param2=:value2 /otherpath/:value2/:splat 301​

# both values - ordering from the browser doesn't matter.
/path/* param1=:value1 param2=:value2 /otherpath/:value1/:value2/:splat 301

Rewrites and Proxying

When you assign an HTTP status code of 200 to a redirect rule, it becomes a rewrite. This means that the URL in the visitor’s address bar remains the same, while Netlify’s servers fetch the new location behind the scenes.

This can be useful for single page apps, proxying to other services, or transitioning for legacy content.

Limitations

Rewrites can be very powerful, but there are a few things they cannot do:

  • For security reasons, rewrites between Netlify sites belonging to different accounts or teams are not allowed.
  • Infinitely looping rules (where the “from” and “to” resolve to the same location) are invalid and will be ignored.
  • By default, we limit internal rewrites to one “hop” — you cannot proxy from Netlify SiteA to Netlify SiteB to Netlify SiteC in a single request. This limitation may be amended for Enterprise customers upon request.

History Pushstate and Single Page Apps

If you’re developing a single page app and want history pushstate to work so you get clean URLs, you’ll want to enable the following rewrite rule:

/*    /index.html   200

This will effectively serve the index.html instead of giving a 404 no matter what URL the browser requests.

Proxying

Just like you can rewrite paths like /* to /index.html, you can also set up rules to let parts of your site proxy to external services. Let’s say you need to communicate from a Single Page App with an API on https://api.example.com that doesn’t support CORS request. The following rule will let you use /api/ from your JavaScript client:

/api/*  https://api.example.com/:splat  200

Now all requests to /api/… will be proxied through to https://api.example.com straight from our CDN servers without an additional connection from the browser. If the API supports standard HTTP caching mechanisms like Etags or Last-Modified headers, the responses will even get cached by CDN nodes.

Note on shadowing

By default, you can’t shadow a URL that actually exists within the site when using a splat or dynamic path segment. This means that even if you’ve setup the following rewrite rule:

/*   /index.html   200

The path /partials/chat.html would still render the contents of that file, if that file actually exists. This tends to be the preferred behavior when setting up rewrite rules for single page apps, etc.

However, if you’re 100% sure that you’ll always want to redirect, even when the URL matches a static file, you can append an exclamation mark to the rule:

/app/*  /app/index.html  200!

This will rewrite everything within /app/* to /app/index.html even if a file matches the URL.

Handling hostnames and protocols differently

All of the examples so far assume configuration “for all hostnames, using the specified paths”. If instead you need to do something special for a domain alias or specific protocol (HTTP vs HTTPS), you’ll want a pattern more like this one:

# http and https need separate rules if you don't force_ssl!
http://blog.yoursite.com/* https://www.yoursite.com/blog/:splat 301!
https://blog.yoursite.com/* https://www.yoursite.com/blog/:splat 301!


# other hostnames might proxy or redirect offsite
https://frontend.yoursite.com/login/* https://backend.yoursite.com/:splat 200

See the above note on shadowing for the reasoning behind the ! — it is presumably the case that you have a /blog/index.html that you’d rather serve than your site’s main index.html in this case!

Note also that for Netlify to work with another hostname than you have configured as the main custom domain, it needs to be assigned to the site somehow — probably as a Domain Alias. Note that you don’t need a Domain Alias to set up a name for a Branch Subdomain.

GeoIP and Language-based redirects

Netlify supports GeoIP and language-based redirects directly from our CDN nodes.

This is ideal for large multi-regional sites where you want to send people to the right location based on their location or browser language.

Both the language and the country can be specified in a cookie as well (nf_lang and nf_country respectively), so you can easily override the default behavior with JavaScript.

When you add these redirect rules, Netlify automatically creates alternate headers to enable the redirection in our CDN nodes. This removes the need for a roundtrip to our origin servers and ensures that normal pages, besides country or language based redirects, are cached on the CDN nodes.

The easiest way to understand these redirect capabilities is to look at some examples:

# Redirect users in China, Hongkong or Taiwan to /china.
# there CANNOT be spaces in the last parameter: Country=x,y,z or Language=xx,yy
/  /china   302  Country=cn,hk,tw
# Redirect users in israel to /israel
/  /israel  302  Country=il

# Redirect users with chinese language preference from /china to /china/zh-cn
/china/*  /china/zh-cn/:splat  302  Language=zh

The system is smart enough to flatten chains of redirect. So in the above case, if a user from China with Chinese language preference visits /china, she’ll get redirected directly to /china/zn-ch in one step. Our cache server will cache this redirect for any other users that would match the same country and language rules.

You can find a list of country codes here: http://dev.maxmind.com/geoip/legacy/codes/iso3166/

And language codes here: http://www.metamodpro.com/browser-language-codes

For languages, note that en will match en-US and en-GB, zh will match zh-tw and zh-hk, etc.

Role-based redirect rules

Role-based redirects let you restrict access to certain paths of your application only to users with granted JWT tokens. This access control is implemented at our CDN edge, removing the need for a round trip to our origin servers. This feature is only available with the Teams Business plan or above.

Before setting up these rules, make sure your JWT client secret is properly configured in our Visitor Access Control panel.

With this feature, you can set role conditions per redirect rule, like this one:

/admin/*	200!	Role=admin

The rule above tells Netlify’s CDN to grant access to the /admin path and everything under it only to users whose JWT tokens include the admin role in their app_metadata. Any other user that tries to access those URLs will be presented with a 404 page.

If you don’t want present a 404 page, you can set a fallback rule to redirect users to a specific page, like a login page. The next example adds a new rule to accomplish that:

/admin/*			200!	Role=admin
/admin/*	/login	401!

The second rule in the example is what we call a fallback rule. It tells Netlify’s CDN that it must redirect every user that’s not in the admin role to a different page.

You can also grant several roles access to the same path by chaining them with commas:

/private/*		200!	Role=editor,admin

You can use this feature with authentication providers like Auth0, Stormpath or any other that can generate JWT tokens with roles metadata. To learn more about JWT tokens and app metadata, you can read more about them JWT specification.

Structured configuration

You can also specify redirect rules in your netlify.toml file. You can create this file in the base directory of your Git repository, if you don’t have one already. We use TOML’s array of tables to specify each individual redirect rule. You can see the list of valid keywords for each rule below:

  • from: The path you want to redirect.
  • to: The URL or path you want to redirect to.
  • status: The HTTP status code you want to use in that redirect, 301 by default.
  • force: Whether to override any existing content in the path or not; false by default.
  • query: The query string parameters REQUIRED to match the redirect. You can read more about Query Params above.
  • conditions: Conditions to match the redirect, like Geo-IP and Role conditions.
  • headers: Additional request headers to send in Proxy Redirects
  • signed: Name of an environment variable to sign Proxy Redirects with.

You can specify any number of rules in your netlify.toml file following that format:

# COMMENT: These are two redirect rules with all the fields expanded
# COMMENT: This is an expanded syntax for rules that won't fit in one line
[[redirects]]
  from = "/old-path"
  to = "/new-path"
  status = 301
  force = false
  query = {path = ":path"} # COMMENT: apply this rule for /old-path?path=example
  conditions = {Language = ["en"], Country = ["US"], Role = ["admin"]}

# COMMENT: This a rule for Single Page Applications
[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

## COMMENT: This rule redirects to an external api signing requests with a secret
[[redirects]]
  from = "/search"
  to = "https://api.mysearch.com"
  status = 200
  force = true # COMMENT: ensure that we always redirect
  headers = {X-From = "Netlify"} # COMMENT: add this header to the search request
  signed = "API_SIGNATURE_TOKEN" # COMMENT: sign each request with the value of this env variable

Custom Headers in Proxy Redirects

With the new structured redirect rules, you can now add a map with custom headers for your proxy redirects, and Netlify will send them with every request:

[[redirects]]
  from = "/search"
  to = "https://api.mysearch.com"
  status = 200
  force = true
  headers = {X-From = "Netlify"}

Signed Proxy Redirects

You can use a JSON Web Signature (JWS) to sign all proxy requests to an external URL. To enable JWS on your requests, Netlify requires a secret token. You can set that token in your site’s build environment variables, and reference it in the redirect rule.

[[redirects]]
  from = "/search"
  to = "https://api.mysearch.com"
  status = 200
  force = true
  signed = "API_SIGNATURE_TOKEN"

The JSON document we sign with this JWS header has this format:

{
  "netlify_id": "the site's id in netlify",
  "site_url": "the site's URL for a given deploy",
  "context": "the deploy context for this request"
}

Testing Redirects

You can test if the rules in your _redirects file are correct at Netlify’s Playground. Copy your rules there and click Test rules. The playground will list all the invalid rules in your file if there are any.

If your rules are valid, they are automatically translated to the structured format, so you can easily migrate from one format to another.

netlify-playground

Netlify Playground is open source and freely distributable. You can read more about it in our blog.


Notice something is incorrect or outdated?

First off, great eye! We appreciate your discovery and want to ensure it gets addressed immediately. Please let us know here.

Want to get started quick?