Photo by PJH on Unsplash

On this page

This chapter follows Astro components.

Astro has no router configuration file. The folder structure under src/pages/ is the route table, and each request loads a full HTML page. That makes Astro a multi-page application by default; client-side navigation is an optional layer on top, covered in Islands and client directives.

File-based routes

Every .astro, .md, .mdx, .html, .js, or .ts file in src/pages/ becomes a route:

File URL
src/pages/index.astro /
src/pages/about.astro /about/
src/pages/blog/index.astro /blog/
src/pages/blog/first-post.md /blog/first-post/
src/pages/rss.xml.ts /rss.xml

Files and folders that start with an underscore (_draft.astro, _components/) are ignored, which lets you keep helpers next to the pages that use them. Link between pages with ordinary <a href> elements; there is no special link component.

Dynamic routes

Brackets in a file or folder name create a parameter. For a static build, Astro must know every value in advance, so the page exports getStaticPaths():

src/pages/tags/[tag].astro
---
import type { GetStaticPaths } from 'astro';
export const getStaticPaths = (() => {
return [
{ params: { tag: 'astro' }, props: { label: 'Astro' } },
{ params: { tag: 'routing' }, props: { label: 'Routing' } },
];
}) satisfies GetStaticPaths;
const { tag } = Astro.params;
const { label } = Astro.props;
---
<h1>Articles tagged {label}</h1>
<p>URL parameter: {tag}</p>

getStaticPaths runs once at build time. Each returned object produces one HTML file. params fills the brackets; props passes data straight to that page so you do not have to look it up again. A route can combine several parameters, such as src/pages/[lang]/[slug].astro.

Rest parameters

[...path] matches any depth, including none:

src/pages/docs/[...path].astro
---
export function getStaticPaths() {
return [
{ params: { path: undefined } },
{ params: { path: 'install' } },
{ params: { path: 'guides/routing' } },
];
}
const { path } = Astro.params;
---
<h1>Docs: {path ?? 'home'}</h1>

This produces /docs/, /docs/install/, and /docs/guides/routing/. This knowledgebase uses nested dynamic folders ([domain]/[area]/[topic]/[slug].astro) to turn each article’s frontmatter into its URL.

Route priority

When several routes could match one URL, Astro picks the most specific. In short: static segments beat dynamic ones, named parameters beat rest parameters, and routes with more segments beat shorter ones. Endpoints and pages follow the same rules.

Diagram 1
flowchart LR
  url["/posts/create"] --> a["posts/create.astro - wins"]
  url -.-> b["posts/[id].astro"]
  url -.-> c["posts/[...slug].astro"]

When two routes are equally specific and would build the same URL, Astro reports a collision instead of guessing.

Endpoints

A .ts or .js file in src/pages/ that exports HTTP method handlers is an endpoint. In a static build it generates a file; with on-demand rendering it runs per request.

src/pages/api/articles.json.ts
import type { APIRoute } from 'astro';
const articles = [
{ slug: 'routing-in-astro', title: 'Routing in Astro' },
{ slug: 'astro-components', title: 'Astro components' },
];
export const GET: APIRoute = () => {
return new Response(JSON.stringify(articles), {
headers: { 'Content-Type': 'application/json' },
});
};

Endpoints return a standard Response. Use them for JSON, RSS feeds, robots.txt, sitemaps, or generated images. Dynamic endpoints use getStaticPaths exactly like pages.

Redirects and error pages

Permanent moves belong in the config, so they apply in both static and server output:

astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
redirects: {
'/old-post/': '/blog/new-post/',
'/blog/[slug]/': '/articles/[slug]/',
},
});

For a static site Astro writes a small HTML file with a meta refresh at the old URL; hosts with an adapter can turn redirects into real HTTP status codes. Inside an on-demand page, return Astro.redirect('/login/') redirects per request.

src/pages/404.astro becomes the not-found page. With on-demand rendering, src/pages/500.astro handles server errors.

Trailing slashes and build format

trailingSlash in the config decides whether /about and /about/ are the same URL: 'always', 'never', or 'ignore'. Pick one and keep links consistent; it affects canonical URLs and how static hosts resolve files. build.format controls whether about.astro becomes about/index.html ('directory', the default) or about.html ('file').

Next: Content collections in Astro.

Check your understanding

Question 1 of 7

0 of 7 checked

  1. 1. What happens to src/pages/_draft.astro?

Search articles

Type a word to search published articles.

Open the search page