The Frontmatter Script

Runs Once, on the Server, Before the Page Goes Out

The Frontmatter Script

Whatever lives between the two `---` fences runs at build time or per request — never in the browser. Use it to fetch data, import components, and compute values.

4 min read Level 1/5 #astro#frontmatter#server
What you'll learn
  • Use the frontmatter to import and compute
  • Use `await` for build-time data fetching
  • Read props and request info from `Astro`

Everything between the two --- fences is server-side TypeScript / JavaScript. It runs once per page render — at build time for static pages, per request for SSR. The browser never sees it.

Three Common Things

1. Import components and helpers

---
import Header from "../components/Header.astro";
import { formatDate } from "../lib/dates.ts";
---

2. Fetch and compute

---
const res = await fetch("https://api.example.com/posts");
const posts = await res.json();
const featured = posts.filter(p => p.featured);
---

3. Read props and the request

---
interface Props {
  title: string;
}
const { title } = Astro.props;
const path = Astro.url.pathname;
---

The Astro Global

The frontmatter has access to an Astro object with everything about the current render. The most useful fields:

FieldWhat it is
Astro.propsProps passed to this component
Astro.paramsURL params for dynamic routes (e.g. [slug])
Astro.urlA URL instance — pathname, searchParams, etc.
Astro.requestThe full Request (server pages only)
Astro.cookiesRead/write cookies
Astro.redirectRedirect to another URL
Astro.slotsProgrammatic access to slot content

No Browser APIs

The frontmatter runs in Node — window, document, localStorage don’t exist there. If you need them, put the code in a <script> tag in the template (or inside an island).

Top-Level Await

The frontmatter is an async context — await works without wrapping anything:

---
const data = await fetch(...).then(r => r.json());
const html = await marked.parse(data.markdown);
---

Imports Anywhere

import only works in the frontmatter. The template half can’t have its own imports. Anything you want to render must be imported above the closing fence.

Up Next

After the script — the template.

The HTML Template →