Layouts

Purpose and Scope

Layouts are Astro components used to provide reusable page structure. In everyday projects, a layout is the component that keeps repeated page chrome, document metadata, navigation, footer markup, and shared styling in one place while allowing each page or Markdown entry to provide its own content. The official Astro terminology is intentionally simple: a layout is still just an Astro component. It can accept props, render a <slot />, import other components, include scripts, and be nested inside another layout when a page needs multiple structural layers.

For a developer working in this repository, the important distinction is between the authoring convention and the build system that eventually renders it. A layout normally lives under src/layouts, but Astro does not treat that directory as a magic runtime boundary. The project source tree is compiled and bundled through package build configuration that treats each package src directory as the build input and emits distributable code into dist. That same source-to-output discipline is visible in the shared TypeScript build configuration used across packages. Sources: configs/tsconfig.build.json

Relevant Source Files

  • .changeset/sharp-bags-build.md - Records a rendering reliability fix for Cloudflare/workerd builds, useful when thinking about page and layout failures during prerendering.
  • .devcontainer/basics/devcontainer.json - Defines the Basics example development container, including the example workspace, forwarded Astro dev port, post-create build, and default page opened in the editor.
  • configs/tsconfig.build.json - Establishes the shared package build contract: package source under src, emitted output under dist, and TypeScript build info kept in a publish-safe cache path.
  • packages/astro-prism/tsconfig.build.json - Shows a package extending the shared build contract while adding its own virtual type file, a pattern used by feature packages that participate in Astro authoring workflows.
  • packages/astro-rss/tsconfig.build.json - Shows another package consuming the shared build contract without extra overrides, useful as a minimal package-build comparison.
  • packages/astro/src/assets/fonts/infra/build-font-file-id-generator.ts - Shows deterministic build-time asset identity for fonts, an implementation detail relevant to layouts that own global typography and page shell assets.

Core Layout Primitives

A full-page layout usually provides the document shell: <html>, <head>, and <body>. Astro’s docs call out one important constraint: if the component includes a page shell, the <html> element must be the parent of all other elements in that component. This makes layouts a natural home for metadata components, global navigation, shared page wrappers, and footer components. Pages then import the layout and pass page-specific values, such as a title, through props. Markdown and MDX content can also use layouts so frontmatter becomes layout input.

The most important layout primitive is <slot />. A slot marks the place where the child page, Markdown body, or nested layout content will be injected. This keeps the reusable structure stable while allowing each route to provide different body content. The tutorial flow in the official docs builds toward this pattern gradually: first reusable layout components, then content passing with <slot />, then frontmatter data, and finally nested layouts. That sequence is a good learning path because it mirrors how real projects evolve from a single page to a blog with shared post structure.

---
import BaseHead from '../components/BaseHead.astro';
import Footer from '../components/Footer.astro';
 
const { title } = Astro.props;
---
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <BaseHead title={title} />
  </head>
  <body>
    <nav>
      <a href="/">Home</a>
      <a href="/posts/">Posts</a>
    </nav>
    <main>
      <h1>{title}</h1>
      <slot />
    </main>
    <Footer />
  </body>
</html>

System-to-Code Mapping

The repository evidence for this page is strongest around how layout authoring fits into local development and builds. The Basics devcontainer runs inside /workspaces/astro/examples/basics, forwards port 4321, installs dependencies, builds the repository, and starts the example with pnpm start --host. It also opens src/pages/index.astro by default, putting a learner directly in a page file where they can import a layout, wrap content, and preview the result. This is the closest source-backed signal for the hands-on Basics layout workflow. Sources: .devcontainer/basics/devcontainer.json

Astro packages share a build model that is useful when reading layout-related implementation code. The shared configs/tsconfig.build.json sets ${configDir}/src as rootDir, ${configDir}/dist as outDir, and includes package source from ${configDir}/src. Feature packages then extend this base. packages/astro-prism/tsconfig.build.json adds ./virtual.d.ts, while packages/astro-rss/tsconfig.build.json uses the default shared build settings. Layout authors usually consume these features indirectly, but maintainers should recognize that layout-friendly APIs are shipped through these package build boundaries. Sources: configs/tsconfig.build.json, packages/astro-prism/tsconfig.build.json, packages/astro-rss/tsconfig.build.json

Layouts often own visible page-level concerns such as syntax-highlighted prose, RSS-linked blog metadata, and global font choices. The requested source set includes one concrete asset implementation: BuildFontFileIdGenerator hashes resolved font file content and appends the font type to produce a build-time file identifier. That implementation does not define the layout API, but it shows the kind of deterministic build artifact generation a layout can rely on when it pulls global typography into a document shell. The page shell stays declarative, while Astro’s build infrastructure makes assets stable and cacheable. Sources: packages/astro/src/assets/fonts/infra/build-font-file-id-generator.ts

Execution Flow

A typical layout workflow starts in a page or content entry. The page imports a layout component, passes props, and places route-specific markup between the layout tags. Astro evaluates the layout component on the server during rendering, resolves props such as Astro.props.title, and injects child content at <slot />. If the project is prerendered, the result is static HTML. If the project uses server rendering, the same component structure still describes the response body, but rendering happens through the server pipeline for each request or on demand.

Because layouts sit around the entire page body, failures inside them can affect every route that uses them. The Cloudflare changeset in this source set records a fix where prerender errors thrown during rendering in workerd could be swallowed, causing astro build to exit successfully while emitting truncated HTML. The change buffers the response body before handing it back to the build process so streaming errors become build failures with clear messages. That matters for layouts because a broken shell component can otherwise produce widespread incomplete pages. Sources: .changeset/sharp-bags-build.md

Authoring Guidance

Create a layout when two or more pages need the same structure, not merely because a file is large. Good candidates are site shells, documentation pages, blog posts, marketing pages, and nested content sections. Keep route-specific content in pages and collection entries, while the layout owns document metadata, landmarks, shared navigation, typography wrappers, and repeated visual rhythm. For blog-style projects, a post layout commonly reads frontmatter-derived props such as title, description, publication date, and author, then renders the Markdown body through <slot />.

Use nested layouts when the common structure has layers. A site-wide layout can provide the document shell and global navigation, while a blog layout can add post metadata and prose styling inside it. This avoids duplicating <html> and <head> responsibilities across many specialized layouts. When nesting, keep the outermost layout responsible for the page shell, and make inner layouts partial UI templates unless they truly need document-level control. That approach matches Astro’s guidance that layouts do not have to provide a full page shell; they are reusable components first and naming conventions second.

Testing and Build Signals

When validating a layout change, use the same signals that the repository’s example environment emphasizes: install dependencies, build the workspace, start the example, and inspect the page in a browser preview on port 4321. For package maintainers, remember that layout-facing capabilities can come from multiple packages that share the TypeScript build base. If a layout uses global font assets, RSS links, or syntax highlighting, failures may show up as rendering errors, emitted asset differences, or package build issues rather than as a problem in the layout file alone.

Next, read astro-components for the component model that layouts build on, astro-pages-routing-basics for how pages choose layouts, and markdown-mdx-content for frontmatter-driven layout usage in content-heavy projects.