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.tsand 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:
- Cloudflare-native. The
@astrojs/cloudflareadapter runs on theworkerdruntime natively. No fighting the platform. - Islands architecture. The whole site ships 0KB of JavaScript by default. Only components that need client-side interactivity get hydrated — like the Three.js
BreathingLatticehero. - Content Collections. First-class MDX support with Zod schema validation. Drop a
.mdxfile insrc/content/blog/and it becomes a page. That’s it. - 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.
In this series View all →
- System Design in Real Life: The 2026 Framework Shootout
- Why I Ditched Next.js for Astro (And Why You Might Too)
- Zero-Cost YouTube Caching on Cloudflare Workers