Astro
Astro is a static site generator that outputs plain HTML. It has its own component syntax (.astro files) that looks like HTML with a frontmatter block.
How Astro files work
Section titled “How Astro files work”---// This runs at BUILD TIME only - not in the browserconst title = "Hello World";const posts = await getCollection('blog');---
<!-- This is the HTML template --><h1>{title}</h1>{posts.map(p => <a href={p.slug}>{p.data.title}</a>)}The --- fences are the frontmatter. Everything inside runs as TypeScript/JavaScript at build time. The HTML below is the output. No JavaScript ships to the browser from this file unless you explicitly add a <script> tag.
Key concepts
Section titled “Key concepts”Static by default
Section titled “Static by default”Every .astro page in src/pages/ becomes a static HTML file. index.astro -> index.html. about.astro -> about/index.html.
No output field = static mode
Section titled “No output field = static mode”Do not add output: "server" or output: "hybrid" to astro.config.mjs. Leaving it out defaults to "static". This is what we want.
Component props
Section titled “Component props”---interface Props { title: string; highlight?: boolean;}const { title, highlight = false } = Astro.props;---<div class:list={["card", { "card--highlight": highlight }]}> <h2>{title}</h2> <slot /> <!-- children go here --></div>Layouts
Section titled “Layouts”Layouts are just components with a <slot />. Pages wrap themselves in a layout:
---import Layout from "../layouts/Layout.astro";---<Layout title="About us"> <h1>About</h1></Layout>Dynamic routes
Section titled “Dynamic routes”src/pages/blog/[slug].astro generates one page per blog post. Requires getStaticPaths():
---export async function getStaticPaths() { const posts = await getCollection('blog'); return posts.map(p => ({ params: { slug: p.slug }, props: { post: p } }));}const { post } = Astro.props;---Content collections
Section titled “Content collections”Blog posts live in src/content/blog/ as Markdown files. Define the schema in src/content.config.ts:
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({ type: 'content', schema: z.object({ title: z.string(), description: z.string(), pubDate: z.date(), tags: z.array(z.string()).default([]), }),});
export const collections = { blog };Fetch posts anywhere:
import { getCollection } from 'astro:content';const posts = await getCollection('blog');Useful Astro APIs
Section titled “Useful Astro APIs”| API | Use |
|---|---|
Astro.url.pathname |
Current page path - used for canonical URL |
Astro.props |
Props passed to this component |
getCollection('blog') |
Fetch all blog posts |
<slot /> |
Where children render in a layout/component |
<Fragment> |
Render multiple elements without a wrapper |
class:list={[]} |
Conditional classes |
set:html={string} |
Render raw HTML (used for JSON-LD) |
is:inline on <script> |
Script runs as-is in the browser, not bundled |
Version
Section titled “Version”We use Astro 7. Check package.json for the exact version. Astro releases frequently - always check the migration guide before upgrading across major versions.