komal.nakrani
Browse Themes
ThemesCategoriesDocsBlogTips & Tricks
Routing••By Komal Nakrani

Redirects in Astro: Config vs Host

Astro redirects three ways: the redirects option in astro.config.mjs, your host's _redirects file for real 301s on static sites, and Astro.redirect() on demand.

#Astro#Routing#Redirects#SEO

Astro supports redirects in three places. The redirects option in astro.config.mjs is the portable choice. On a static site with no adapter, it produces HTML pages with a meta refresh rather than true HTTP redirects. For real 301 responses on a static site, add a _redirects file to public/ on hosts that support it (Netlify and Cloudflare Pages). Inside on-demand pages, return Astro.redirect('/new/', 301).

Key Takeaways

  • redirects in config works everywhere, but on static builds it’s a meta refresh with no status code.
  • With an adapter, Astro can pass config redirects to the host as real HTTP redirects.
  • public/_redirects gives true 301s on Netlify and Cloudflare Pages without an adapter.
  • Use Astro.redirect() for runtime decisions, such as auth checks.

1. The redirects config option

// astro.config.mjs
import { defineConfig } from 'astro/config';

export default defineConfig({
  redirects: {
    '/old-about/': '/about/',
    '/blog/[slug]/': '/articles/[slug]/',
    '/promo/': { status: 302, destination: '/pricing/' },
  },
});

Dynamic segments work when the pattern matches on both sides. /blog/[slug]/ redirects every post that exists as an /articles/[slug]/ page.

What gets built depends on your setup:

  • Static, no adapter: Astro writes an HTML file at the old path with <meta http-equiv="refresh"> and a canonical link to the destination. Browsers follow it; search engines generally treat it as a redirect, but there’s no 301 status.
  • With an adapter: adapters for Netlify, Vercel and Cloudflare can turn config redirects into the host’s native redirect rules, so they return real status codes.

2. Host redirect files

For a static site that needs real 301s, use the host’s own format.

Netlify and Cloudflare Pages read _redirects from the output root. Put it in public/ and Astro copies it to dist/:

# public/_redirects
/old-about/      /about/          301
/blog/old-post/  /blog/new-post/  301
/docs/*          /guides/:splat   301

Cloudflare Pages also reads _headers the same way. Rules are matched top to bottom, so put specific rules before wildcards.

Vercel uses vercel.json:

{
  "redirects": [
    { "source": "/old-about/", "destination": "/about/", "permanent": true }
  ]
}

GitHub Pages has no server-side redirects. Use the config option and accept meta refreshes.

3. Runtime redirects

On a page rendered on demand, return Astro.redirect() from the frontmatter:

---
export const prerender = false;
const user = Astro.locals.user;
if (!user) return Astro.redirect('/login/', 302);
---

In endpoints and middleware, use context.redirect() or return a Response with a Location header. The default status is 302. Use 301 or 308 only for moves that are truly permanent, since browsers cache them hard.

Which to choose

Situation Use
Renamed a few pages, any host redirects in config
Static site on Netlify or Cloudflare, SEO matters public/_redirects
Site uses an adapter redirects in config (adapter emits host rules)
Redirect depends on cookies or user Astro.redirect()
Hundreds of legacy URLs Host redirect file, generated by a script

Avoid redirect chains

Each hop costs a round trip, and crawlers may stop following after a few. When a page moves twice, update the first rule to point at the final destination. Also keep the trailing slash consistent on both sides so a redirect doesn’t land on a URL that redirects again; the trailing slash tip explains how trailingSlash affects this.

The Astro routing guide covers how redirects fit with route priority, and the Cloudflare deploy docs show where _redirects lives in a theme. The full option reference is in the Astro routing docs.

FAQ

Does the Astro redirects option return a 301?

Only with an adapter that supports it. On a static build without an adapter, it generates a meta refresh page, which has no HTTP status code.

Where do I put a _redirects file in Astro?

In public/. Astro copies it to the root of dist/, where Netlify and Cloudflare Pages read it.