Astro Best Practices for Static Sites
Building static sites with Astro? Here’s a comprehensive list of best practices and conventions that will help you create fast, maintainable, and scalable projects.
🚀 Performance First
1. Zero JS by Default
Astro ships zero JavaScript to the browser by default. Only add client-side JS when absolutely necessary.
<!--Static by default - no JS-->
<button>Click me</button>
<!--Only hydrate when needed-->
<ReactComponent client:visible />
2. Use Appropriate Hydration Directives
client:load
- Hydrate immediately (use sparingly)client:idle
- Hydrate when browser is idleclient:visible
- Hydrate when component enters viewportclient:media
- Hydrate at specific breakpointsclient:only
- Skip server rendering entirely
3. Optimize Images
Always use Astro’s built-in <Image />
component for automatic optimization:
import heroImage from '/images/hero.jpg';---<Image src={heroImage} alt="Description" />
📁 Project Structure
4. Follow Astro’s Conventions
src/
├── components/ # Reusable components
├── layouts/ # Page layouts
├── pages/ # File-based routing
├── content/ # Content collections
├── styles/ # Global styles
└── assets/ # Images, fonts, etc.
5. Use Content Collections
For any content-heavy features (blog, docs, portfolio), use Content Collections:
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
schema: z.object({
title: z.string(),
publishDate: z.date(),
description: z.string(),
}),
});
6. Leverage File-Based Routing
pages/index.astro
→/
pages/about.astro
→/about
pages/blog/[slug].astro
→/blog/:slug
pages/[...slug].astro
→ Catch-all routes
🎨 Component Best Practices
7. Prefer Astro Components
Use .astro
components for static content. They’re lighter than framework components:
export interface Props {
title: string;
variant?: 'primary' | 'secondary';
}
const { title, variant = 'primary' } = Astro.props;---<button class={`btn btn-${variant}`}>
{title}
</button>
8. Extract Reusable Logic
Keep components focused and extract shared logic:
export function formatDate(date: Date) {
return new Intl.DateTimeFormat('en-US').format(date);
}
// Component.astro
import { formatDate } from '@/utils/formatDate';
const formattedDate = formatDate(new Date());---```
### 9. **Use TypeScript**
Astro has excellent TypeScript support. Use it for better DX:
```astro---import type { CollectionEntry } from 'astro:content';
interface Props {
post: CollectionEntry<'blog'>;
}
const { post } = Astro.props;---```
## 🎯 Data Fetching
### 10. **Fetch at Build Time**
Leverage Astro's static generation by fetching data in frontmatter:
```astro---// This runs at build time
const response = await fetch('https://api.example.com/data');
const data = await response.json();---<ul>
{data.map(item => <li>{item.name}</li>)}
</ul>
11. Use getStaticPaths for Dynamic Routes
const posts = await getCollection('blog');
return posts.map(post => ({
params: { slug: post.slug },
props: { post },
}));
}
const { post } = Astro.props;---```
## 🔧 Development Workflow
### 12. **Use Path Aliases**
Configure path aliases in `tsconfig.json`:
```json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@layouts/*": ["src/layouts/*"]
}
}
}
13. Enable Prefetching
Add prefetching for near-instant page navigations:
<a href="/about" data-astro-prefetch>About</a>
<!--Or enable globally in config-->
export default defineConfig({
prefetch: true
});
14. Use Environment Variables
Keep sensitive data secure:
API_KEY=secret_key
// Component.astro
const apiKey = import.meta.env.API_KEY;---```
## 🎭 Styling Best Practices
### 15. **Scope Styles by Default**
Astro automatically scopes styles in components:
```astro
<style>
/* Only applies to this component */
h1 {
color: purple;
}
</style>
16. Use CSS Variables for Theming
:root {--color-primary: #0066cc;--spacing-unit: 8px;
}
.button {
background: var(--color-primary);
padding: calc(var(--spacing-unit) * 2);
}
17. Import Global Styles Once
import '@/styles/global.css';---```
## 🛠️ Build Optimization
### 18. **Minimize Third-Party Scripts**
When you must use external scripts, load them efficiently:
```astro
<!--Defer non-critical scripts-->
<script defer src="analytics.js"></script>
<!--Use type="module" for modern JS-->
<script type="module" src="app.js"></script>
19. Configure Build Output
Optimize your build output:
// astro.config.mjs
export default defineConfig({
build: {
inlineStylesheets: 'auto',
format: 'file', // or 'directory'
},
});
20. Use Compression
Enable compression in your hosting platform or use Astro’s compression integration.
📋 Common Patterns
21. Layout Composition
import Header from '@/components/Header.astro';
import Footer from '@/components/Footer.astro';---<html>
<body>
<Header />
<slot />
<Footer />
</body>
</html>
22. Conditional Rendering
const items = ['one', 'two', 'three'];---{showBanner && <div>Banner</div>}
{items.length > 0 && (
<ul>
{items.map(item => <li>{item}</li>)}
</ul>
)}
23. Error Handling
try {
const response = await fetch('/api/data');
data = await response.json();
} catch (error) {
console.error('Failed to fetch data:', error);
data = { fallback: true };
}---```
## ✅ Deployment Checklist
### 24. **Before Deploying**
- Run `astro check` for TypeScript errors
- Test build locally with `astro build && astro preview`
- Check all environment variables are set
- Verify meta tags and SEO elements
- Test on multiple devices/browsers
- Enable caching headers
### 25. **Choose the Right Adapter**
- Static hosting: No adapter needed (Netlify, Vercel, GitHub Pages)
- SSR: Use appropriate adapter (`@astrojs/node`, `@astrojs/vercel`)
- Hybrid: Configure `output: 'hybrid'` for mixed static/dynamic
## 🎯 Key Takeaways
1. **Ship Less JavaScript** - Use Astro components and hydrate sparingly
2. **Build-Time Over Runtime** - Fetch data during build when possible
3. **Type Everything** - Use TypeScript for better developer experience
4. **Follow Conventions** - Stick to Astro's project structure
5. **Optimize Assets** - Use built-in image optimization
6. **Think Static First** - Only add dynamic features when necessary
Remember: Astro is designed for content-focused websites. Embrace its static-first philosophy, and you'll build incredibly fast sites with great developer experience.---*New to Astro? Check out the [official documentation](https://docs.astro.build) and join the [Discord community](https://astro.build/chat) for help!*