Click any item to expand the explanation and examples.
📝 Components
.astro component structure basics
---
// Frontmatter (runs at build time on the server)
const title = "Hello";
const items = await fetch("https://api.example.com/items").then(r => r.json());
---
<!-- Template (HTML output) -->
<h1>{title}</h1>
<ul>
{items.map(item => <li>{item.name}</li>)}
</ul>
<style>
/* Scoped to this component */
h1 { color: blue; }
</style>
Props basics
---
// Card.astro
interface Props {
title: string;
url: string;
description?: string;
}
const { title, url, description = "No description" } = Astro.props;
---
<a href={url}>
<h3>{title}</h3>
<p>{description}</p>
</a>
<!-- Usage -->
<Card title="My Post" url="/blog/my-post" />
Slots basics
---
// Layout.astro
const { title } = Astro.props;
---
<html>
<head><title>{title}</title></head>
<body>
<header><slot name="header" /></header>
<main><slot /></main>
<footer><slot name="footer">Default footer</slot></footer>
</body>
</html>
<!-- Usage -->
<Layout title="Home">
<h1 slot="header">Welcome</h1>
<p>Main content here</p>
</Layout>
📂 Routing
File-based routing routing
src/pages/
index.astro → /
about.astro → /about
blog/index.astro → /blog
blog/[slug].astro → /blog/my-post
blog/[...slug].astro → /blog/2024/01/my-post (catch-all)
404.astro → Custom 404 page
Dynamic routes routing
---
// src/pages/blog/[slug].astro
import { getCollection } from 'astro:content';
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map(post => ({
params: { slug: post.id },
props: { post },
}));
}
const { post } = Astro.props;
const { Content } = await post.render();
---
<h1>{post.data.title}</h1>
<Content />
📚 Content Collections
Define and query collections content
// src/content.config.ts
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
schema: z.object({
title: z.string(),
pubDate: z.date(),
tags: z.array(z.string()).optional(),
draft: z.boolean().default(false),
}),
});
export const collections = { blog };
---
// Query posts
import { getCollection } from 'astro:content';
const posts = await getCollection('blog',
({ data }) => !data.draft
);
const sorted = posts.sort((a, b) =>
b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
);
---
🏝️ Islands (Client-Side Interactivity)
client: directives islands
---
import Counter from './Counter.react';
import Search from './Search.svelte';
---
<!-- Load JS immediately -->
<Counter client:load />
<!-- Load JS when visible in viewport -->
<Search client:visible />
<!-- Load JS when browser is idle -->
<Counter client:idle />
<!-- Load JS on specific media query -->
<Sidebar client:media="(min-width: 768px)" />
<!-- No directive = zero JS (static HTML only) -->
<Counter />
⚙️ Config & CLI
astro.config.mjs and CLI config
// astro.config.mjs
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
import tailwind from '@astrojs/tailwind';
import sitemap from '@astrojs/sitemap';
export default defineConfig({
site: 'https://example.com',
integrations: [react(), tailwind(), sitemap()],
output: 'static', // or 'server' for SSR
});
npm create astro@latest # New project
npx astro dev # Dev server
npx astro build # Production build
npx astro preview # Preview build locally
npx astro add react # Add integration
See also: What is Astro? | Tailwind CSS cheat sheet