Migrating from Next.js to Astro: My Escape from Framework Hell

How I replaced 50MB of Next.js complexity with a lean Astro + Hono stack that deploys in seconds. Spoiler: Next.js was the problem all along.

This blog you're reading right now was rebuilt from scratch this week. What started as a simple AI-powered technical blog became a lesson in why the JavaScript ecosystem's obsession with complexity is actively harmful to developers.

The Original Sin: Choosing Next.js

When I first built this site, I reached for Next.js like most developers do. It's the "industry standard," right? React, server components, the whole ecosystem. What could go wrong?

Everything, as it turns out.

The OpenNext Nightmare

To deploy Next.js on Cloudflare Workers, you need OpenNext - a compatibility layer that attempts to make Next.js work outside Vercel's walled garden. The key word here is attempts.

Error: Cannot read properties of undefined (reading 'default')

This error haunted me for days. The culprit? The otpauth library I used for 2FA doesn't play nicely with Next.js's edge runtime. The "solution" was to remove the explicit edge runtime declaration entirely and hope the framework figured it out.

But that's just the tip of the iceberg.

Build Times from Hell

A simple blog with a handful of pages:

Metric Next.js + OpenNext Astro
Build time 45-60 seconds 3 seconds
Bundle size 2.5MB+ 230KB
Cold start 800ms+ 45ms
Dependencies 847 packages 359 packages

Read that again. 3 seconds versus nearly a minute. For a blog.

The Astro Revelation

After one too many "Cannot read properties of undefined" errors, I asked myself: Why am I fighting this framework?

The answer: I shouldn't be.

What Astro Gets Right

Astro's philosophy is refreshingly simple: ship less JavaScript. For a content-focused site like a blog, this is exactly right.

// astro.config.mjs - The entire config
export default defineConfig({
  output: 'server',
  adapter: cloudflare({
    platformProxy: { enabled: true },
  }),
});

That's it. No next.config.js with 47 experimental flags. No middleware.ts that may or may not work depending on the deployment target. No wrestling with App Router vs Pages Router.

Native Cloudflare Support

The @astrojs/cloudflare adapter just works. D1 databases, Workers AI, KV storage - all accessible directly:

// Access bindings in any Astro page or API route
const runtime = (Astro.locals as any).runtime;
const db = runtime.env.DB;
const ai = runtime.env.AI;

No OpenNext. No compatibility layers. No prayer-based deployment.

API Routes Done Right

For the API layer, Astro's native API routes are clean and predictable:

// src/pages/api/posts/[id].ts
export const GET: APIRoute = async ({ params, locals }) => {
  const db = (locals as any).runtime.env.DB;
  const post = await getPostById(db, parseInt(params.id));
  return new Response(JSON.stringify(post), {
    headers: { "Content-Type": "application/json" },
  });
};

No hidden magic. No wondering if your route is running on the edge or in Node.js.

The Migration

The actual migration took about 4 hours:

  1. Scaffold Astro project with Cloudflare adapter
  2. Port the lib functions (auth, db, blog-generator) - mostly copy-paste
  3. Convert pages from React to Astro components
  4. Create API routes using Astro's native API route support
  5. Add scheduled handler for cron triggers via a post-build script

The hardest part? Remembering I don't need "use client" directives anymore.

The Results

After deploying the Astro version:

  • Build + Deploy: 16 seconds total (vs 2+ minutes)
  • Worker startup: 45ms (vs 800ms+)
  • Bundle size: 231KB gzipped (vs 2.5MB+)

The site feels instant. Because it is.

Why Next.js is a Trap

Next.js has become the jQuery of 2026 - a framework people reach for by default without questioning whether it's appropriate.

For Vercel's platform? Next.js is probably fine. They've optimized their infrastructure around its quirks.

For everywhere else? You're fighting uphill. The framework assumes Vercel. The documentation assumes Vercel. The community troubleshooting assumes Vercel.

If you're deploying to Cloudflare, AWS, or anywhere that isn't Vercel, you're a second-class citizen using compatibility layers written by heroic open-source maintainers trying to make a Vercel-shaped peg fit into a standard-shaped hole.

The Takeaway

Use the right tool for the job.

  • Need a complex React app with lots of client interactivity? Maybe Next.js makes sense (on Vercel).
  • Building a content site, blog, documentation, or marketing page? Use Astro.
  • Deploying to Cloudflare Workers? Use Astro.

The JavaScript ecosystem's complexity addiction is a choice. You can choose differently.


This post was written on a blog that now deploys in 16 seconds instead of 2 minutes.