Mastering Astro and Vite
Astro has quietly become one of the most interesting frameworks for content-heavy sites. Its islands architecture is a genuine paradigm shift — most of your page is static HTML, with interactive React/Vue/Svelte components hydrated only where needed.
Why Astro Changes the Default
Every other framework starts from the assumption that JavaScript is the default. Astro inverts this: HTML is the default, JavaScript is opt-in.
The practical result: a typical blog or marketing page ships zero kilobytes of framework JavaScript. The client doesn’t need to hydrate the entire component tree just to display text.
Islands Architecture Explained
An “island” is a component that requires client-side interactivity. Everything else is static.
---
// This component is server-rendered — zero JS shipped
import StaticCard from '@/components/StaticCard.astro';
// This component ships JavaScript
import InteractiveWidget from '@/components/InteractiveWidget.tsx';
---
<StaticCard title="No JS here" />
<InteractiveWidget client:visible />
The client: directives control when the island hydrates:
| Directive | When it hydrates |
|---|---|
client:load | Immediately on page load |
client:idle | When browser is idle |
client:visible | When scrolled into view |
client:media | When a media query matches |
Vite Under the Hood
Astro uses Vite as its build tool and dev server. This means you get:
- Native ESM in development — no bundling, instant HMR
- Rollup-powered production builds — tree-shaking, chunk splitting
- First-class TypeScript — no extra configuration required
The Vite config in Astro is exposed via astro.config.mjs:
import { defineConfig } from 'astro/config';
import tailwindcss from '@tailwindcss/vite';
export default defineConfig({
vite: {
plugins: [tailwindcss()],
// Full Vite config access here
},
});
Content Collections: Type-Safe Markdown
Astro’s content collections give you Zod-validated frontmatter with full TypeScript inference:
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
date: z.string(),
tags: z.array(z.string()),
}),
});
Now getCollection('blog') returns fully typed entries — no more typos in frontmatter keys.
Performance Results
Running Lighthouse on an Astro site versus the equivalent Next.js version:
- FCP: 0.4s vs 1.2s
- TTI: 0.5s vs 2.8s
- Total JS: 12 KB vs 180 KB
The numbers speak for themselves for content-focused pages.
When Not to Use Astro
Astro shines for content sites. For highly interactive applications (rich dashboards, real-time collaborative tools), Next.js or SvelteKit may be better fits. Know your use case.
Getting Started
npm create astro@latest my-site
cd my-site
npm run dev
The setup wizard is excellent and worth running through even if you know what you’re doing.