Explainer · Build Log

Why I Ditched Next.js for Astro (And Why You Might Too)

A real migration story: moving useaitechdad.com from Next.js 15 to Astro 6 on Cloudflare — the problems, the architecture, the Lighthouse 100 money shot.

The Problem

The current site was running Next.js 15 on Cloudflare Pages. It worked, but it had a few problems that kept nagging:

  • YouTube content was hardcoded. Adding a new playlist meant editing config.ts and redeploying.
  • RSS scraping was unreliable. YouTube quietly blocks RSS scrapers. Videos would disappear from the site with no warning.
  • No blog. Every time I wanted to write a long-form breakdown, I had nowhere to put it.
  • Vercel lock-in. Next.js 15’s full feature set assumes Vercel. Running it on Cloudflare means giving up RSC streaming, some middleware features, and fighting the adapter constantly.

Why Astro

Six frameworks were on the table. The comparison video covers the full elimination game. Here’s the short version of why Astro won for this use case:

  1. Cloudflare-native. The @astrojs/cloudflare adapter runs on the workerd runtime natively. No fighting the platform.
  2. Islands architecture. The whole site ships 0KB of JavaScript by default. Only components that need client-side interactivity get hydrated — like the Three.js BreathingLattice hero.
  3. Content Collections. First-class MDX support with Zod schema validation. Drop a .mdx file in src/content/blog/ and it becomes a page. That’s it.
  4. Server output with selective prerendering. Static pages (/, /about, /blog/*) go to the CDN. Dynamic pages (/videos, /videos/[id]) run as Cloudflare Workers.

The Architecture

output: 'server'  (Cloudflare Workers)

     ├── /                     → prerender = true  (CDN, Lighthouse 100)
     ├── /about                → prerender = true  (CDN)
     ├── /blog/[slug]          → prerender = true  (CDN, Lighthouse 100)

     ├── /videos               → DYNAMIC (YouTube API → KV cache)
     └── /videos/[playlistId]  → DYNAMIC (YouTube API → KV cache)

The YouTube integration is the interesting part. See the companion post on KV caching for the full technical breakdown.

The Result

  • Lighthouse Performance: 100 on every static page
  • Time to first byte on dynamic pages: < 50ms (Cloudflare edge)
  • YouTube API quota used per day: < 200 units (out of 10,000 free)
  • Monthly cost: $0

The video walkthrough of the full migration is on the channel.

More in Build Log