Redirects and rewrites (_redirects)
A _redirects file in your site tells the network what to do with addresses that have moved, or that don’t match a file. It uses the same format as Netlify and Cloudflare Pages, so a file you already have usually works unchanged.
It applies to Level 0 (public) sites only. See Scope and limits.
Where the file goes
Section titled “Where the file goes”Put _redirects in the root of your build output, next to your home page’s index.html. Most generators copy a static folder into the output unchanged, so put the file there:
| Generator | Put _redirects in |
|---|---|
| Astro, Vite, Qwik City | public/ |
| VitePress | docs/public/ (your source folder’s public/) |
| Hugo, Docusaurus, Gatsby | static/ |
| Eleventy | Any folder you pass through to the output |
| Jekyll | The site root, with include: [_redirects] in _config.yml |
The file travels with your site. It deploys and rolls back with the content it belongs to.
Syntax
Section titled “Syntax”One rule per line: the address to match, where to send it, and an optional status.
# Lines that start with # are comments/old-page /new-page/ 301/blog/* /news/:splat 301/:year/:slug /posts/:slug 301/shop https://shop.example.com/ 302fromis a path on your site, starting with/.tois a path on your site, or a full URL on another site.- Status defaults to
301if you leave it out. *at the end offrommatches the rest of the path. Use:splatintoto carry it over.:namematches one path segment. Use the same:nameinto.
Statuses
Section titled “Statuses”| Status | What it does |
|---|---|
301 |
Permanent redirect. The visitor’s address bar changes. |
302 |
Temporary redirect. The visitor’s address bar changes. |
200 |
Rewrite. Serves the target’s content at the address that was asked for. The address bar doesn’t change. |
404 |
Serves the target’s content with a 404 status. Use it for a not-found page for one section. See Custom 404 pages. |
307 and 308 aren’t supported.
A rewrite (200) can only serve a file from your own site. It can’t point at another site.
Which rule wins
Section titled “Which rule wins”-
A real file wins over a rule. If your site has a file at the requested path, it’s served, and the rule is skipped. Add
!to the status to force the rule to apply anyway:/old /new/ 301! -
Exact rules (no
*or:name) are checked first. -
Pattern rules are checked in the order they appear in the file. The first match wins.
-
If two rules have the same
from, the first one is used.
The first point is what makes a single-page-app fallback work. This rule sends every unknown path to your app, but still serves your real scripts, styles and images:
/* /index.html 200A path counts as having a real file if the file exists at that path, or if an index.html exists in a folder of that name.
Routing settings
Section titled “Routing settings”Two optional lines turn on routing behaviour for the whole site. Each is written as a comment, so the file still works on other hosts.
Add a trailing slash
Section titled “Add a trailing slash”# ee:trailing-slash onMany generators write each page as a folder with an index.html inside: about/index.html, served at /about/. Without this line, /about (no slash) is a 404. With it, /about redirects to /about/.
It applies to any path whose last part has no dot and no trailing slash. Your own rules are checked first, so it never adds an extra step in front of a redirect you wrote.
With Astro, also set trailingSlash: 'always' and build: { format: 'directory' } in astro.config.mjs, so your site’s own links use the slash.
Clean URLs
Section titled “Clean URLs”# ee:clean-urls onSome generators write flat files (about.html) but link to /about. With this line, /about is served from about.html, and the address bar stays on /about.
Generators that need it: Quartz, Observable Framework, Hono’s SSG helper, vite-ssg, Silex, îles and Emanote by default, and VitePress, Rspress, VuePress and HonKit when their cleanUrls option is on.
- A real file still wins.
/LICENSEservesLICENSEeven ifLICENSE.htmlexists. about.htmlcounts as the page at/about. A rule of your own for/aboutonly applies if you force it with!.- With both settings on,
/aboutservesabout.htmlwhen it exists, and redirects to/about/only when it doesn’t. /about.htmlstill works as well. Your generator’s canonical tag tells search engines which address you prefer.
Common recipes
Section titled “Common recipes”Move one page:
/pricing-2025 /pricing/ 301Move a whole section, keeping the rest of each address:
/blog/* /news/:splat 301Send a section to another site:
/docs/* https://docs.example.com/:splat 301A single-page app, where every unknown path loads the app:
/* /index.html 200A not-found page for one section:
/docs/* /docs/404.html 404Scope and limits
Section titled “Scope and limits”-
Level 0 sites only. Encrypted sites (Level 1 and Level 2) don’t read
_redirects. See encryption levels. -
307and308aren’t supported. -
Rewrites stay on your site. A
200rule that points at another site is refused. -
Conditions aren’t supported. Netlify’s
Country=,Language=,Role=andCookie=conditions, rules that match on query parameters, and rules whose source is a full domain all stop the deploy. -
Up to 2,000 rules per file.
-
Redirects are cached for 5 minutes by browsers, so a rule you remove stops applying soon after your next deploy.
-
The file isn’t downloadable. A request for
/_redirectsgets a 404. -
Some paths belong to the network and can’t be redirected or used for your own files:
- the files visitors’ browsers use to load your site:
/ee.js,/ee-worker.js,/brotli_wasm.wasm; - exactly
/healthand/discover; /_header,/_index,/_blocks,/_torrent,/_digestand anything under/_piece/;- anything under
/.ee/.
Paths such as
/health/team,/discover/productsand/ee/docs/are yours. - the files visitors’ browsers use to load your site:
Checking your file
Section titled “Checking your file”Your file is checked when you deploy, from the portal or the command line. The deploy stops, and names each line, if the file has:
- a rule with no target, or a target that isn’t a path or a full URL;
- a status other than
301,302,200or404; - a rule that redirects to itself, or a chain of rules that loops;
- a rewrite (
200) or404rule whose target is on another site, or isn’t a file in your site; - a condition, a query-parameter match or a domain-level source;
- a rule for a path that belongs to the network;
- more than 2,000 rules.
Two rules with the same from only produce a warning, since the first one is used.
The deploy also prints what it found, for example _redirects: 3 rule(s), trailing-slash: on, clean-urls: off. Check that line if a routing setting doesn’t seem to apply: a tool that strips comments can remove the setting without any other sign.
To check a rule after deploying, request the old address and look at the status and Location:
curl -sI https://www.example.com/old-page