Muhammad Zulfan Wahyudin
Back to Blog

Astro vs Next.js: Why Astro Wins for Content-First Websites

· 6 min read
  • astro
  • nextjs
  • frontend
  • web-development
  • comparison

An honest comparison between Astro and Next.js for content-first sites — performance, architecture, developer experience, and when to choose which.

The Content-First Dilemma

Every time I start a new project — a blog, documentation site, landing page, or marketing site — the first question is always the same: Astro or Next.js?

Both are modern web frameworks. Both support React, TypeScript, and Markdown. But their approaches are fundamentally different.

This post breaks down the real-world differences between Astro and Next.js for content-first websites, complete with a comparison table and guidance on when to pick which.

Architecture: Static-First vs Server-First

The most fundamental difference lies in their rendering philosophy.

AspectAstroNext.js
Default renderingStatic (zero JS)Server-side (React Server Components)
JavaScript per pageMinimal — only interactive components (islands)Every page is a React component — bigger bundle
HydrationPartial — opt-in interactivity per componentFull page hydration (except RSC)
OutputStatic HTML files or SSR (via adapter)Server-rendered React (SSR) or static export (limited)
Build timeFast — content renders straight to HTMLSlower — needs React runtime at build

Astro is Zero JS by default. If a page doesn’t need interactivity, Astro sends zero bytes of JavaScript to the browser.

// Astro — pure HTML, zero JS on the client
---
const { title } = Astro.props;
---
<h1>{title}</h1>
// Next.js — even as a server component, React runtime stays in the bundle
export default function Page({ title }: { title: string }) {
  return <h1>{title}</h1>;
}

Next.js 14+ with the App Router and React Server Components does reduce client-side JavaScript. But the React runtime itself is still part of the bundle. In Astro, if you don’t use a framework (React/Vue/Svelte) at all, your JS bundle can be 0 KB.

Bottom line: For content-first sites — blogs, documentation, marketing pages — Astro crushes it on raw performance metrics.

Islands Architecture

Astro’s Islands pattern lets you use React for interactive components (e.g. navbar, form, comment section) while keeping the rest as static HTML.

---
// Astro — partial hydration
import Navbar from "../components/Navbar.tsx";
import BlogContent from "../components/BlogContent.astro";
---

<!-- Interactive component: JS sent to client -->
<Navbar client:load />

<!-- Pure HTML: zero JavaScript -->
<BlogContent post={post} />

Next.js has no “islands” concept. Every page is a React component top to bottom. If you need interactivity in one small component, the entire page still carries the React bundle.

Developer Experience

AspectAstroNext.js
Setupnpm create astro@latest — 30 secondsnpx create-next-app — 1-2 minutes
File-based routingYes, similar to Next.jsYes, App Router
Markdown/MDX supportFirst-class — built inRequires extra config
Content collectionsBuilt-in with schema validationNone — needs third-party (Contentlayer, next-mdx-remote)
Image optimizationBuilt-in @astrojs/imageBuilt-in next/image
CSS supportGlobal CSS, scoped styles, TailwindCSS Modules, Tailwind, CSS-in-JS
Plugin ecosystemAstro integrations (100+)React ecosystem (more mature)

Content Collections

This is one of Astro’s killer features. Define a schema for your blog frontmatter and get type safety + auto-validation:

// src/content/config.ts — Astro
import { defineCollection, z } from 'astro:content';

const blog = defineCollection({
  schema: z.object({
    title: z.string(),
    description: z.string(),
    pubDate: z.date(),
    tags: z.array(z.string()).optional(),
  }),
});

In Next.js, you’d need to set up Contentlayer or next-mdx-remote yourself to get equivalent functionality.

Performance: Real-World Comparison

Here’s performance data for the same use case — a blog with 100 Markdown articles:

MetricAstroNext.js (SSG)Next.js (SSR)
Lighthouse Performance10095-10085-95
Total JS per page0-15 KB~70 KB React + ~20 KB page~70 KB React + ~20 KB page
HTML size~5 KB~5 KB + JSON chunks~15 KB (server rendered)
Build time (100 pages)~5 seconds~15 secondsN/A (runtime)
TTFB (CDN)<50ms<50ms~100-200ms

Note: Next.js SSG with output: 'export' can achieve good performance, but the React runtime still stays in the bundle.

When to Choose Astro

  • Building a blog, documentation site, marketing site, or landing page
  • Your content is primarily Markdown/MDX
  • Performance and Core Web Vitals are top priorities
  • You want the smallest possible bundle size
  • Small team — Astro is simpler with a shallower learning curve

When to Choose Next.js

  • Building a web application (dashboard, SaaS, social media)
  • You need complex dynamic routing, middleware, or API routes
  • Your team is already comfortable with the React ecosystem
  • You need advanced features like ISR (Incremental Static Regeneration)
  • Heavy integration with databases and authentication

Hybrid Approach: Best of Both Worlds

Many teams use Astro for content pages and Next.js for application pages:

your-site/
├── astro-app/        → Blog, docs, landing pages (Astro)
└── next-app/         → Dashboard, user settings (Next.js)

Or you can use Astro with React Islands — keep your existing React components while getting much lighter performance.

Conclusion

Astro and Next.js aren’t competitors that replace each other. They have different sweet spots:

Content-first sites → Astro (maximum performance)
Application-heavy  → Next.js (rich ecosystem)

If your project’s priority is delivering content fast, Astro is the right choice. Its zero-JS-by-default architecture, partial hydration, and content collections give you a smooth developer experience without worrying about performance optimization.

Since migrating this portfolio from Next.js to Astro, Lighthouse scores went from 85-90 to 98-100. Build time dropped from 30 seconds to 3 seconds. Most importantly — there’s no more runtime JavaScript sent to the browser without a reason.

Have a project in mind? Let's build something together.

Get in Touch