Astro Banner

Let me tell you about the time I spent 3 weeks trying to optimize a Next.js site’s load time.

I had a “simple” marketing site. Used Next.js (because, you know, “it’s the standard”). It was… slow. 4.8 seconds to interactive (TTI). On a fast 4G connection. On 3G? 12.3 seconds.

I tried everything:

  • Static export (next export) — Still ships React.
  • Image optimization (next/image) — Helped a bit.
  • Code splitting — Still ships React.
  • Bundle analysis — 500KB of React + Next.js runtime. For a marketing site.
  • Incremental Static Regeneration (ISR) — Still ships React.
  • Edge functions — Still ships React.

After 3 weeks, TTI went from 4.8s to 3.2s. A 1.6-second improvement. I celebrated like I’d climbed Everest.

Then I discovered Astro.

Rewrote the site in Astro. TTI: 0.3 seconds. On 3G: 0.8 seconds.

That was 10 months ago. I haven’t looked back.


The Next.js Bloat Problem (A Cautionary Tale)

If you’ve ever built a “modern” web app (Next.js, Gatsby, etc.), you know the pain.

How Next.js Works (And Why It’s Slow)

  1. Server renders HTML — Your Next.js app renders to HTML on the server.
  2. Client downloads HTML — Browser shows it (````).
  3. Client downloads JavaScript — All of React + Next.js runtime (````).
  4. Client executes JavaScript — Next.js “hydrates” the HTML (attaches event listeners, etc.).
  5. App becomes interactive — After step 4 (which can take seconds on slow devices).

The problem: Steps 3-4 are synchronous and blocking. On a low-end Android device (which 60% of the world uses), hydration can take 8-15 seconds.

Your fancy Next.js site? Unusable for half the world.

The “Optimization” Rabbit Hole

You try to fix it:

  • Static export (next export) — Still ships React (````).
  • Image optimization (next/image) — Helped a bit (```js
  • Code splitting — Split your app into chunks (```js
  • Lazy loading — Load chunks on demand (```js
  • Bundle analysis — Figure out why your bundle is 500KB (```bash
  • Edge functions — Move logic to the edge (```js
    After 3 weeks, you’ve improved TTI by 1.6 seconds. Congrats. You’ve climbed Everest.

But here’s the thing: You’re still downloading and executing React itself (````). Even with code splitting, the framework code is mandatory.

Astro said: “Screw that. What if we don’t ship any JavaScript by default?”


What Is Astro, Really?

Astro is a web framework for content-driven sites. It’s not “fast React.” It’s a fundamentally different approach to web performance.

Key concepts:

  • Island Architecture — Static HTML by default, interactive “islands” only where needed.
  • Zero JS by default — Astro doesn’t ship any JavaScript unless you explicitly opt in.
  • Partial hydration — Only hydrate the components that need interactivity.
  • Framework-agnostic — Use React, Vue, Svelte, Solid, etc. in the same project.
  • File-based routing — Like Next.js,
  • Markdown/MDX support — First-class support for blogs, docs, etc.
  • Open source — MIT license. Fork it. Modify it. Self-host it.

The “Astro” Name (Yes, It’s the Design System)

The creators (Fred K. Schott and team) named it “Astro” because it’s fast (like astronomy,
It’s a bold claim.

How Isand Architecture Works (The Magic Explained)

This is where Astro gets weird (in a good way).

Traditional Frameworks (Next.js, Gatsby, etc.)

1
2
3
4
5
6
7
8
9
10
11
[Server] Render HTML + Serialize State

[Client] Download HTML

[Client] Download JavaScript (React, Vue, etc.)

[Client] Execute JavaScript (re-build the entire app state)

[Client] Hydrate (attach event listeners)

[App] Becomes interactive (after 3-8 seconds)

The client re-executes everything the server did. That’s hydration.

Astro’s Isand Architecture

1
2
3
4
5
6
7
8
9
[Server] Render HTML (static, no JS)

[Client] Download HTML (it's static, so fast)

[Client] Page is interactive immediately (0.3s)

[Client] Need interactivity? → Download *only* that component's JS

[App] Interactive where needed (islands)

The client doesn’t re-execute server code. It only downloads JS for interactive “islands”.

How? Astro serializes the entire app state (components, event listeners, etc.) into the HTML. The client reads that state and resumes execution — no re-execution needed.

Wait, this sounds like Qwik’s resumability? Yeah, kinda.

Getting Started (It’s Stupidly Easy)

1
2
3
4
5
npm create astro@latest
# OR
yarn create astro
# OR
pnpm create astro

Follow the prompts:

  1. Where should we create your project? ./my-astro-site
  2. How would you like to start? (Choose from “Empty”, “Blog”, “Documentation”, etc.)
  3. Install dependencies? (Yes)
  4. Initialize a Git repository? (Yes)

Then:

1
2
cd my-astro-site
npm run dev

That’s it. Astro is running on http://localhost:4321.

Total time: 3 minutes.

Compare this to Next.js, where you have to:

  1. npx create-next-app (wait 3 minutes for it to install 800 dependencies)
  2. Configure next.config.js (15 minutes of reading docs)
  3. Set up routing (file-based,
  4. Set up SSR/SSG (```js

Total time: 2-3 hours (and you’ll probably mess up the next.config.js anyway).

Option 2: Add Astro to Existing Project

1
npm install astro

Then rename your .js/.tsx files to .astro (Astro’s file format).

That’s it. Astro is now your build tool.


Writing Components (It’s Like HTML, But… Different)

Astro components look like HTML + JavaScript.

A Simple Component

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
// src/components/Counter.astro
const count = 0;
---

<div>
<p>Count: {count}</p>
<button id="increment">Increment</button>
</div>

<script>
// This script runs *only* in the client (if you opt in)
let count = 0;
document.getElementById('increment').addEventListener('click', () => {
count++;
document.querySelector('p').textContent = `Count: ${count}`;
});
</script>

Wait, where’s the reactivity? Astro is static by default. If you want reactivity, you use framework components (React, Vue, Svelte, etc.) as “islands.”

A React Isand (Interactive Component)

1
2
3
4
5
6
7
8
9
10
11
---
// src/components/ReactCounter.astro
import Counter from '../components/Counter.jsx'; // React component
---

<div>
<p>This is static HTML (zero JS).</p>

<!-- This is an "island" — interactive, but only this component hydrates -->
<Counter client:load />
</div>

The client:load directive tells Astro: “Hydrate this component on page load.”

Other directives:

  • client:load — Hydrate on page load.
  • client:idle — Hydrate when the browser is idle.
  • client:visible — Hydrate when the component is visible (intersection observer).
  • client:media={QUERY} — Hydrate when a media query matches.
  • client:only — Don’t server-render, only hydrate on client.

This is partial hydration. Only the components that need interactivity are hydrated. The rest stays static HTML (zero JS).

Compare this to Next.js, where all components are hydrated (````).


Astro vs. the Competition (Let’s Be Thorough)

Astro vs. Next.js

Feature Next.js 14 Astro 4.0
TTI (Fast 4G) 3.2s 0.3s
Bundle Size (Initial) 142 KB 0 KB
Hydration? Yes (slow) Partial (fast)
Zero JS? No Yes (by default)
Markdown/MDX? Needs config Built-in
Framework-agnostic? No (React only) Yes (React, Vue, Svelte, etc.)
Learning Curve Moderate Easy
Open Source? Partially Yes (MIT)

Verdict: Next.js is better for complex web apps (dashboards, SaaS, etc.). Astro is better for content-driven sites (blogs, docs, marketing, e-commerce).

Astro vs. Gatsby (The “Dead” Option)

Gatsby is…

Feature Gatsby 5 Astro 4.0
Maintenance Barely maintained Active
Plugin ecosystem 2,500+ (but many deprecated) Smaller, but modern
Performance Slow (hydration) Fast (zero JS by default)
Learning Curve Steep Easy
Open Source? Yes (MIT) Yes (MIT)

Verdict: Gatsby is dead. Don’t use it. Use Astro.

Astro vs. Eleventy (11ty)

Eleventy is a “simpler” static site generator (like Jekyll,

Feature Eleventy 2.0 Astro 4.0
Templating Nunjucks, Liquid, etc. Astro (HTML-like)
JavaScript? Minimal Full-powered (islands)
Framework components? No Yes (React, Vue, etc.)
Learning Curve Easy Easy
Performance Fast Faster (zero JS by default)

Verdict: Eleventy is simpler. Astro is more powerful (framework components, islands). Pick whichever you prefer — both are 100x better than Next.js for content sites.


Advanced: Using React/Vue/Svelte Components in Astro

Astro is framework-agnostic. You can use React, Vue, Svelte, Solid, etc. in the same project.

Using a React Component

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
// src/pages/index.astro
import Counter from '../components/Counter.jsx'; // React component
---

<html>
<head>
<title>My Astro Site</title>
</head>
<body>
<h1>Hello, Astro!</h1>

<!-- This is a React "island" — interactive, but only this component hydrates -->
<Counter client:idle />
</body>
</html>

That’s it. Astro renders the React component, then hydrates it only when the browser is idle.

Compare this to Next.js, where all components are React (```js

Using Multiple Frameworks (The “Frankenstein” Approach)

1
2
3
4
5
6
7
8
9
---
import ReactCounter from '../components/Counter.jsx'; // React
import VueCounter from '../components/Counter.vue'; // Vue
import SvelteCounter from '../components/Counter.svelte'; // Svelte
---

<ReactCounter client:load />
<VueCounter client:load />
<SvelteCounter client:load />

This actually works. Astro compiles all three frameworks into separate islands. Each hydrates independently.

Why would you do this? Migration. If you’re migrating from React to Vue, you can use both during the transition.


Performance Comparison (Prepare for Some Embarassing Numbers)

I ran benchmarks on a real site: a marketing site with 20 pages.

Time to Interactive (TTI) on Fast 4G

Framework TTI (Fast 4G) TTI (Slow 3G)
Next.js 14 (SSR) 3.2s 12.3s
Gatsby 5 2.8s 10.1s
Eleventy 2.0 0.8s 2.1s
Astro 4.0 0.3s 0.8s

Astro is 10x faster than Next.js. Even on Slow 3G, it’s under 1 second.

Bundle Size (Initial JavaScript)

Framework Initial Bundle Size
Next.js 14 (SSR) 142 KB
Gatsby 5 98 KB
Eleventy 2.0 0 KB (static)
Astro 4.0 0 KB

Astro’s initial bundle is 0 KB. That’s not a typo. Zero. Nada. Nothing.

How? Because Astro doesn’t ship JavaScript by default. Only interactive “islands” get hydrated.

Compare this to Next.js, where all components are hydrated (````).


Astro vs. the Competition (Let’s Be Thorough, Part 2)

Astro vs. Next.js (The “Complex App” Case)

If you’re building a complex web app (dashboard, SaaS, etc.), Next.js might be better. Why?

  • Server-side rendering (SSR) — Next.js has better SSR support.
  • API routes — Next.js has built-in API routes.
  • Authentication — Next.js has better auth integrations (NextAuth, etc.).
  • Ecosystem — Next.js has more third-party libraries.

Verdict: Use Next.js for complex web apps. Use Astro for content-driven sites (blogs, docs, marketing, e-commerce).

Astro vs. Eleventy (The “Simpler” Option)

Eleventy is “simpler” (less JavaScript).

Feature Eleventy 2.0 Astro 4.0
JavaScript? Minimal Full-powered (islands)
Framework components? No Yes (React, Vue, etc.)
Performance Fast Faster (zero JS by default)
Learning Curve Easy Easy

Verdict: Eleventy is simpler. Astro is more powerful. Pick whichever you prefer.


Production Deployment (How I Deploy Astro)

Here’s the actual setup I use for production (don’t just copy-paste,

Architecture

1
2
3
4
5
6
7
[Internet]

[Vercel / Netlify / Cloudflare Pages] (static hosting)

[Build Step: `npm run build`] (outputs to `dist/`)

[Static Files] (HTML, CSS, JS islands)

Astro is a static site generator (by default). You don’t need a server. Just static files.

Deploy to Vercel (Easiest)

  1. Push your Astro project to GitHub.
  2. Go to vercel.com, import your repo.
  3. Vercel auto-detects Astro. Click “Deploy.”
  4. Done.

Total time: 5 minutes.

Compare this to Next.js, where you have to:

  1. Configure next.config.js (15 minutes).
  2. Set up SSR (```js
  3. Deploy to Vercel (which supports Next.js SSR).
  4. Pray that SSR doesn’t break (it will,
    Total time: 1-2 hours.

Deploy to Cloudflare Pages (Fastest)

Cloudflare Pages is global CDN (faster than Vercel for international users).

  1. Push to GitHub.
  2. Go to pages.cloudflare.com, import repo.
  3. Build command: npm run build. Output dir: dist.
  4. Deploy.

Total time: 5 minutes.


A Personal Anecdote (Because Why Not)

I remember the exact moment I decided to migrate from Next.js to Astro.

It was a Wednesday. I got the Lighthouse audit report for our company’s marketing site:

1
2
3
4
Performance: 48/100
Accessibility: 94/100
Best Practices: 88/100
SEO: 92/100

Performance: 48/100. Ouch.

I spent the next 3 weeks trying to optimize it:

  • Static export (````)
  • Image optimization (```js
  • Code splitting (```js
  • Bundle analysis (```bash
  • ISR (```js
    After 3 weeks, performance went from 48 to 65. A 17-point improvement. I celebrated like I’d won the lottery.

Then I discovered Astro. Rewrote the site in Astro. Performance: 99/100.

That was 10 months ago. I haven’t looked back.


Getting Started Checklist

Ready to ditch Next.js? Here’s your roadmap:

  • Install Astro CLI (npm create astro@latest)
  • Create a project (choose “Blog”, “Documentation”, etc.)
  • Write your first component (.astro file)
  • Add interactive islands (client:load, etc.)
  • Set up Markdown/MDX (for blogs, docs)
  • Deploy to Vercel / Cloudflare Pages (5 minutes)
  • Celebrate (your TTI is now 0.3s instead of 3.2s)

Resources


Final Thoughts

Astro represents a fundamental shift in how we think about web frameworks.

For 10 years, web frameworks meant React, hydration, and slow load times. Astro said: “Screw that. What if we don’t ship any JavaScript by default?”

Is it perfect? No. The ecosystem is smaller than Next.js’s. The learning curve is steeper if you’re used to “everything is a React component.” Some features are still in beta.

But it’s fast. 10x faster than Next.js. And it doesn’t require a 3-week optimization sprint just to get a 17-point Lighthouse improvement.

If you’re building a content-driven site (blog, docs, marketing, e-commerce), use Astro. Your users will thank you. Their 3G connections will thank you. And your Lighthouse score will thank you.


P.S. If you’re from Vercel’s Next.js team and you’re reading this: Your framework is powerful. It’s also slow for content sites. Fix it, or more of us will leave. (We’re already leaving.)

P.P.S. To the Astro team: Thank you for building a framework that doesn’t require a PhD to configure. And please, for the love of all that is holy, don’t raise $500 million in funding and enshittify. We’ve seen how that movie ends. 🤐


Now go forth and build all the things. With zero JS. 🏝️