What is Astro?
Astro is a web framework that ships zero JavaScript by default. It renders your pages to static HTML at build time and only hydrates interactive components when needed. The result: blazing-fast content sites that score 100/100 on Lighthouse.
Why Astro?
- Zero JS by default — pages ship as pure HTML/CSS
- Islands architecture — only interactive components get JavaScript
- Use any framework — React, Vue, Svelte, Solid components in the same page
- Content Collections — type-safe Markdown/MDX with frontmatter validation
- Built-in optimizations — image compression, CSS inlining, prefetching
- SSR + SSG — static or server-rendered, your choice per page
Quick Start
npm create astro@latest my-site
cd my-site && npm run dev
Page Routing (File-Based)
---
// src/pages/index.astro
import Layout from '../layouts/Layout.astro';
import Card from '../components/Card.astro';
const posts = await fetch('https://api.example.com/posts').then(r => r.json());
---
<Layout title="My Blog">
<h1>Latest Posts</h1>
<div class="grid">
{posts.map(post => (
<Card title={post.title} href={`/blog/${post.slug}`} />
))}
</div>
</Layout>
<style>
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
</style>
Content Collections (Type-Safe Markdown)
// 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()),
draft: z.boolean().default(false)
})
});
export const collections = { blog };
---
// src/pages/blog/[...slug].astro
import { getCollection } from 'astro:content';
export async function getStaticPaths() {
const posts = await getCollection('blog', ({ data }) => !data.draft);
return posts.map(post => ({
params: { slug: post.slug },
props: post
}));
}
const post = Astro.props;
const { Content } = await post.render();
---
<Layout title={post.data.title}>
<h1>{post.data.title}</h1>
<time>{post.data.pubDate.toLocaleDateString()}</time>
<Content />
</Layout>
Islands (Partial Hydration)
---
import StaticHeader from '../components/Header.astro'; // No JS
import ReactCounter from '../components/Counter.jsx'; // Interactive
import VueSearch from '../components/Search.vue'; // Interactive
---
<StaticHeader /> <!-- Ships as HTML, zero JS -->
<ReactCounter client:visible /> <!-- Hydrates when scrolled into view -->
<VueSearch client:idle /> <!-- Hydrates when browser is idle -->
<!-- client:load = immediate, client:visible = IntersectionObserver, client:idle = requestIdleCallback -->
API Routes
// src/pages/api/subscribe.ts
import type { APIRoute } from 'astro';
export const POST: APIRoute = async ({ request }) => {
const { email } = await request.json();
await db.insert(subscribers).values({ email });
return new Response(JSON.stringify({ success: true }), { status: 200 });
};
Astro vs Alternatives
| Feature | Astro | Next.js | Gatsby | Hugo |
|---|---|---|---|---|
| Default JS | Zero | React runtime | React runtime | Zero |
| Framework | Any | React only | React only | Go templates |
| Build speed | Fast | Medium | Slow | Fastest |
| Content | Collections | MDX/CMS | GraphQL | Markdown |
| Islands | Native | Partial (RSC) | No | No |
| Lighthouse | 100/100 | 80-95 | 70-90 | 100/100 |
Real-World Impact
A marketing site on Next.js shipped 350KB of JavaScript — Lighthouse score: 67. Same content, same design, rebuilt with Astro: 12KB of JavaScript (only the newsletter form). Lighthouse: 100. Page load time dropped from 3.2s to 0.8s. Organic traffic increased 40% within 2 months.
Building high-performance content sites? I help teams optimize web performance. Contact spinov001@gmail.com or explore my data tools on Apify.
Top comments (0)