Astro has quietly become the go-to framework for content-heavy websites — blogs, documentation, marketing sites, portfolios. Here's why it's winning.
Astro's philosophy: HTML and CSS are enough for most content. JavaScript should only load when the component actually needs it.
---
// This code runs at BUILD TIME (server/node)
// Never ships to the browser
import { getPosts } from '../lib/posts';
const posts = await getPosts();
---
<!-- Pure HTML output — zero JS shipped -->
<html>
<body>
<h1>My Blog</h1>
{posts.map(post => (
<article>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
<a href={`/posts/${post.slug}`}>Read more</a>
</article>
))}
</body>
</html>Astro's killer feature: interactive components (islands) load independently with zero overhead for the static parts.
---
import SearchBar from '../components/SearchBar.react.tsx';
import Newsletter from '../components/Newsletter.svelte';
---
<!-- Static HTML — no JS -->
<h1>My Blog</h1>
<p>Some static content...</p>
<!-- This React component loads ONLY when user can see it -->
<SearchBar client:visible />
<!-- This Svelte component loads on page load (needed for interactivity) -->
<Newsletter client:load />client:visible — loads JS only when the component scrolls into view.
client:load — loads immediately.
client:idle — loads when browser is idle.
client:media — loads based on CSS media query.
import ReactComponent from './Component.react.tsx';
import VueComponent from './Component.vue';
import SvelteComponent from './Component.svelte';
import SolidComponent from './Component.solid.tsx';
<!-- All work. Use the best tool for each island. -->
<ReactComponent client:load />
<VueComponent client:visible />
<SvelteComponent client:idle />On content sites migrated to Astro:
Built-in type-safe content management:
// src/content/config.ts
import { z, defineCollection } from 'astro:content';
const blog = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
date: z.date(),
tags: z.array(z.string()),
}),
});
export const collections = { blog };---
import { getCollection } from 'astro:content';
const posts = await getCollection('blog');
// Fully typed. TypeScript errors if schema doesn't match.
---✅ Blogs (exactly your use case!) ✅ Documentation sites ✅ Marketing/landing pages ✅ Portfolios ✅ E-commerce product pages (with React islands for cart)
❌ Highly interactive apps (use Next.js or Remix) ❌ Real-time data dashboards ❌ Web apps with lots of user state
For your blog specifically, Vivek — Astro is worth seriously considering.