This skill provides production-grade guidance for Astro projects — from initial scaffolding through deployment, caching, and performance tuning. It covers the patterns that actually matter in real projects and the mistakes that actually happen.
Read this file first for the core workflow and decision tree.
Consult the reference files in references/ for deep dives on specific topics:
references/setup-and-structure.md — Project creation, file structure, config, adaptersreferences/rendering-modes.md — SSG vs SSR vs Hybrid, when to use each, caching strategiesreferences/seo.md — Meta tags, Open Graph, JSON-LD, sitemaps, canonical URLsreferences/islands-and-vue.md — Island architecture, client directives, Vue/React/Svelte integrationreferences/content-and-data.md — Content collections, data fetching, dynamic routesreferences/deployment.md — Adapters, static hosts, serverless, environment variablesreferences/performance.md — Image optimization, bundle analysis, hydration controlreferences/troubleshooting.md — Common errors and fixes organized by symptomWhen helping with an Astro project, follow this sequence:
This is the single most important decision in any Astro project. Everything else flows from it.
output: 'static' in config and use export const prerender = false on dynamic pages.Only needed for SSR or hybrid:
@astrojs/vercel (serverless or edge)@astrojs/netlify@astrojs/cloudflare@astrojs/node (standalone or middleware)Add only what you need. Each integration is a potential build-time dependency:
bash
# Common additions
npx astro add vue # Vue islands
npx astro add tailwind # Tailwind CSS
npx astro add mdx # MDX support
npx astro add sitemap # Auto sitemap generation
.astro pages in /src/pagesDon't bolt it on later. See references/seo.md for the full pattern, but at minimum:
<SEO> component for head tags@astrojs/sitemapEvery page should use a layout. Layouts handle <html>, <head>, and shared chrome:
astro
---
// src/layouts/Base.astro
import SEO from '../components/SEO.astro';
const { title, description } = Astro.props;
---
<html lang="en">
<head>
<SEO title={title} description={description} />
</head>
<body>
<nav><!-- shared nav --></nav>
<slot />
<footer><!-- shared footer --></footer>
</body>
</html>
Static by default. Only hydrate what needs interactivity:
astro
<!-- Static: renders HTML, ships zero JS -->
<Card title="Hello" />
<!-- Interactive: hydrates on load -->
<Counter client:load />
<!-- Interactive: hydrates when visible (lazy) -->
<ImageGallery client:visible />
The #1 Astro mistake: forgetting client:* on a component that needs interactivity,
then wondering why click handlers don't work.
SSR without caching is just a slow website. Always pair SSR with a caching strategy:
ts
// In an SSR endpoint or page
return new Response(JSON.stringify(data), {
headers: {
"Cache-Control": "public, s-maxage=60, stale-while-revalidate=300",
"Content-Type": "application/json"
}
});
Read references/troubleshooting.md for a symptom-based guide. The top 5 issues:
client:* directivepackage.jsonoutput mode in configWhen generating Astro project files:
---) even if empty.astro extension for Astro components and pagessrc/pages/, components in src/components/, layouts in src/layouts/astro.config.mjs with only the integrations and settings actually needed