- Start Date: 2023-05-22
- Reference Issues: #466
- Implementation PR: withastro/astro#7067
Add a redirects
config option to the Astro config which allows you to define redirects in a central place. Allow integrations to read this information and apply it to it's own redirects configuration for deployment.
New config option used like so:
import { defineConfig } from 'astro/config';
export default defineConfig({
redirects: {
'/other': '/place'
}
});
You can also specify the status code by using an object notation:
import { defineConfig } from 'astro/config';
export default defineConfig({
redirects: {
'/other': {
status: 302,
destination: '/place'
}
}
});
This was original proposed as a stage 1 discussion here and was one of the top voted proposals.
As websites age there are times where routes are rearchitectured. In order preserve existing links to content on the web it is common to set up redirects in your web server.
Redirect configuration varies depending on what web server or host you use. Some times you might even want to change hosts, in which case your redirects need to be converted over to a new format.
Having a redirects configuration within Astro itself allows a single place to define redirects that works everywhere.
- Works in development mode.
- Writes out
<meta http-equiv="refresh">
tags in static builds. - Gives proper hooks to integrations so that they can write to their own configuration.
- Dynamic behavior that goes beyond the capabilities of the file-based routing system. So nothing based on the properties of the request, user session, etc. Regular routes still should be used for this scenario.
- Redirects to pages that do not exist in the Astro project.
- External redirects.
This will be implemented as a feature of the internal routing. The RouteData
type will be extended to include:
interface RedirectConfig = string | {
status: 300 | 301 | 302 | 303 | 304 | 307 | 308;
destination: string;
}
export interface RouteData {
type: 'redirect';
// ...
redirect?: RedirectConfig;
redirectRoute?: RouteData;
}
Our core rendering handles routing and will detect this type of route and return a Response
with a status code in the 3xx range with the Location
header set to the value of the route's redirect
property.
When using the object notation { destination: string; status: number; }
the status code specified there will be used. Otherwise the default is 301
for GET
requests and 308
for any other method.
Dynamic routes are supported through the same syntax as in the file-based routing system. For example, if a site moved its blog it might set up a redirect like so:
import { defineConfig } from 'astro/config';
export default defineConfig({
redirects: {
'/blog/[...slug]': '/team/articles/[...slug]'
}
});
In SSG mode this will call the destinations getStaticPaths
method to get valid static paths. Those paths will be used to generate the HTML files for the redirects.
Redirects will use the priority assignment algorithm as file-system routing. For example, you could have a file system route /src/pages/blog/contributing.astro
and a redirect route /blog/[...slug]
. If these were both filesystem routes you would expect contributing.astro
to be prioritized over the spread route. This is the case with redirects a well.
In the case of exact matches, the file-system route will be prioritized (by being ordered first in the list). This is meant to match the behavior of host systems (such as Netlify).
Currently the static generation code throws for any non-200 response. With this change it will now accept any 3xx as a valid response codes. It will generate an HTML doc that looks like:
`<!doctype html>
<title>OLD_LOCATION</title>
<meta http-equiv="refresh" content="0;url=LOCATION" />
Adapters can integrate with this new route type through the astro:build:done
hook which includes the routes
property. This is an array of route datas that were built. Redirects will be part of this array.
Additionally adapters can disable the HTML generation via a new configuration value build.redirects
which can be set to false
. Users can also set this value, but it is more likely to come from an integration via the astro:config:setup
hook:
export default {
hooks: {
'astro:config:setup': ({ updateConfig }) => {
updateConfig({
build: {
redirects: false
}
});
}
}
}
Adapters who have their own configuration files, such as the Netlify and Cloudflare _redirects
file, will disable HTML generation because the host serves HTML before it checks configuration.
- We have existing redirect tests for SSR. These will be updated to test SSG redirect behavior for:
redirects
config- Redirects created via
Astro.redirect()
andnew Response
as those are now enabled by this change.
- Adds some new complexity to the config.
- New type of route in the RouteData.
- There could be some expectations that all adapters handle this perfectly. This is a good expectation! We should do our best to make sure as many adapters support this as possible.
- The HTML based fallback still does work.
The other major design would be to allow defining redirects in the file where the page now lives. For example in a markdown page you could do:
---
redirect_from:
- /one
- /two
---
This method is nice because it is file-based and in the file where the redirect is ultimately going to go to.
The major problem with this design is that we need to load and process every page before we know about these routes. So this would significantly slow down dev, where we don't need to know about all pages until they are requested.
A secondary problem with this alternative is that it's not clear how we should define redirects in non-Markdown pages, for example in an API route how would you define them? Via special comment syntax? The export const foo
pattern from prerender?
- This is a small change and can go through in the next minor release.