astro routing & layouts

[check: …]
📖 Full guide → 📖 ASTRO_ROUTING_LAYOUTS.md — the complete narrative, code samples, and verified sources. This page is its interactive companion.

The one rule

The filesystem IS the router: a file under src/pages/ becomes a URL. [brackets] = a dynamic segment; [...rest] = catch any depth; a layout wraps a page via <slot/>.

There is no routing config to maintain in Astro. Drop a file in src/pages/ and a route appears. Dynamic routes need getStaticPaths() in static output. Layouts live in src/layouts/ by convention — but they are just components that render <slot/> where the page's content goes.

file = route [param] = dynamic [...rest] = catch-all <slot/> = where the page goes getStaticPaths = the route list (SSG)

The routing visualizer — click a URL, see the route + layout

Left: the curated src/ tree (mirrors Astro's rules). Right: type a URL (or click a sample) and the resolver shows which file matches, the params it receives, and which layout wraps it. The resolver below is a faithful model of Astro's match order — static beats named-param beats rest.

static segment [param] [...rest]

The <slot/> — how a layout wraps a page

A layout is an ordinary Astro component. It renders the page shell (<html>/<head>/<body>) plus a <slot/> placeholder. The page imports the layout and passes its unique markup as the layout's children — Astro injects those children where the <slot/> sits.

src/layouts/Base.astro
<html><head><title>{title}</title></head> <body> <nav>…</nav>
<slot />  ← page content injected here
<h1>Hello, world</h1>
<p>This markup came from src/pages/index.astro</p>
<footer>…</footer> </body></html>
▲ the page's children flow up into the layout's <slot/>
src/pages/index.astro
---
import Base from '../layouts/Base.astro';
const { title } = Astro.props; // title is passed INTO the page from its caller
---
<Base title="Home">
  <h1>Hello, world</h1>
  <p>This markup came from src/pages/index.astro</p>
</Base>

The layout reads its own props with const { title } = Astro.props;. Layouts nest by importing one layout inside another and wrapping it the same way — the inner layout's <slot/> receives the outer page content.

Route priority — who wins when routes collide

When more than one file could build the same URL, Astro sorts by specificity. The resolver above implements this order (static > named param > rest).

PriorityRuleExample match
1Reserved routes (_astro/, _action/, _server_islands/)internal Astro assets & features
2More path segments wins over fewer/posts/[...slug] beats /[...slug] for /posts/a
3Static route beats dynamicposts/create.astro beats posts/[id].astro for /posts/create
4Named param [x] beats rest [...x]blog/[slug] beats blog/[...path] for /blog/hello
5Prerendered dynamic beats on-demand (SSR) dynamicstatic-generated page wins over server-rendered match
6Endpoints beat pagesdata.json.ts beats data.astro
7File-based routes beat configured redirectsa real file shadows a redirects entry
8Tie → sorted alphabetically by Node's default localelast resort, deterministic on one machine

Prefix a file/folder with _ (e.g. _utils.js) to exclude it from routing — handy for colocating components and tests next to pages.

Verified against docs.astro.build/en/guides/routing + /basics/layouts (primary) and the CloudCannon layouts tutorial (secondary). Sibling bundles: 🔗 astro_content_collections (content feeds these routes) · 🔗 astro_islands.