Every comparison of these two ends up measuring the wrong thing. Astro ships less JavaScript, Next.js has more features, both are fast when used properly, and none of that tells you which one your project should use.
The useful question is narrower: are the pages you are building documents that occasionally do something, or an application that happens to have pages? Get that answer right and the framework follows from it. Get it wrong and you spend two years fighting the tool.
I use both — this site is Astro, most client applications are Next.js — so here is the decision as I actually make it, including the cases where I have changed my mind.
What is the actual difference?#
Where JavaScript ends up by default. Everything else follows from that one decision.
| Astro | Next.js | |
|---|---|---|
| Default output | HTML, no JS | HTML plus a React runtime |
| Interactivity | Opt in, per component | Available everywhere |
| Routing | File-based, static by default | File-based, server by default |
| State across pages | None — full navigations | Preserved by the client router |
| Best at | Content that is mostly read | Applications that are used |
Astro renders components to HTML at build time and ships nothing to the browser unless you ask. Next.js ships a React application that renders on the server first. Both produce fast first loads; they differ in what happens afterwards.
That difference is invisible on a landing page and decisive on a dashboard, which is exactly why the framework argument never resolves — people are describing different projects.
When is Astro obviously right?#
When most of the page is content, and interactivity is a handful of islands rather than the substance of the thing.
- Marketing sites, portfolios, documentation. The page is read, not operated. Shipping a component runtime to render text is paying for something the page never uses.
- Blogs and content sites. Content collections or a CMS, static output, and a CDN. This site is 65 static pages with one small script.
- Anything where the first paint is the product. Cold traffic gives you seconds; HTML that is already painted beats a runtime that has to boot.
- Sites where a page is genuinely independent — no shared state to preserve across a navigation, so a full page load costs nothing.
The last point is the one that decides it more often than bundle size. If moving between pages does not need to preserve anything — a half-filled form, an open panel, a websocket, a media player — then the client-side router earns nothing and you are paying for it in every byte.
There is a second-order benefit that rarely appears in comparisons: a site with no client runtime has far fewer ways to break. No hydration mismatch, no effect running twice, no state desynchronised from the URL. The page you rendered is the page the reader gets, and the class of bugs that comes from re-running your UI on the client simply does not exist.
Islands are the escape hatch, and they are enough#
Astro renders a React, Vue or Svelte component to HTML and hydrates only the ones you mark. A search box, a filter, a modal — each is an island with its own runtime, and the rest of the page stays static.
---
import Filter from '../components/Filter.tsx';
---
<Filter client:visible /> <!-- hydrates when it scrolls into view -->
<article set:html={content} /> <!-- never hydrates --> client:visible rather than client:load is the habit worth forming: below-the-fold interactivity does not need to be ready before it is on screen, and deferring it moves work out of the critical path for free.
When is Next.js obviously right?#
When the page is a surface for doing things, and the things share state.
- Dashboards and admin tools. Filters, tables, drawers, live data. Every one of those is a stateful component and there are dozens of them.
- Anything behind a login where the session shapes the whole page and navigation should not reload the app shell.
- Products with real-time or streaming UI — a chat, a feed, an AI response arriving token by token.
- Teams already fluent in React who will build faster in one mental model than two.
The last one is not a technical argument and it is frequently the strongest one available. A framework the team knows produces working software sooner than the theoretically better one they are learning.
It is also worth being clear that "application" is not a size claim. A five-page internal tool with a login and a table is an application; a two-hundred-page documentation site is not. The number of routes tells you nothing about which model fits — what the routes *do* tells you everything.
Server components change the calculus#
The App Router lets most of a Next.js page render on the server with no client JavaScript, which narrows the gap considerably. A well-built server-component page ships a fraction of what a pages-router equivalent did.
It narrows the gap; it does not close it. The React runtime is still there for the client components you do use, and the discipline required to keep a Next.js page light is real work — whereas in Astro, light is the default and heaviness is opt-in. Defaults decide what a codebase looks like after a year of people being busy.
What does the wrong choice actually cost?#
Different things in each direction, and one of them is much worse.
| Wrong choice | What it costs | Recoverable? |
|---|---|---|
| Astro for an application | Fighting the model — state across pages, shared layouts, client routing | Painful; a rewrite of the interactive core |
| Next.js for a content site | A heavier bundle and more configuration than needed | Yes — it still works, it is just not optimal |
The asymmetry matters. Next.js on a marketing site is a mild inefficiency; Astro on a stateful application is a structural fight you keep losing. When genuinely unsure, that asymmetry is an argument for Next.js — the failure mode is cheaper.
It is worth separating the two directions clearly, because people treat them as symmetric and they are not. Over-provisioning costs bytes; under-provisioning costs architecture. Bytes can be optimized later by someone with an afternoon. Architecture is optimized later by someone with a quarter.
Where I have changed my mind: I used to reach for Astro on anything content-shaped. Now I check whether the content site will grow an account area, a dashboard, or anything with a session. If that is on the roadmap rather than hypothetical, starting in Next.js avoids a migration that always arrives at a bad moment.
What does each get wrong in practice?#
Every framework has a failure mode its own documentation is quiet about. Knowing them is worth more than another benchmark.
Astro: the island that should have been a page#
The temptation is to solve a growing interactive need by making the island bigger. One client:load component becomes the whole page, holding its own state and routing internally — at which point you have a single-page application inside a static site, with none of the framework support a real one would have. When an island starts wanting a router, it is telling you something.
Astro: content collections outgrowing the filesystem#
Markdown files are excellent until somebody who does not use git needs to edit them. Moving to a CMS later is straightforward for the data and annoying for everything that assumed a synchronous filesystem read. If a non-developer will ever edit the content, wire the CMS on day one.
Next.js: the accidental client component#
One useState at the top of a component marks it and everything it renders as client code. A layout that acquires a hook drags the whole tree into the bundle, and nothing warns you — the page still works, it is just heavier every week. Watching bundle size in CI is the only reliable defence.
Next.js: caching that surprises you#
Fetch caching, route segment config and revalidation are powerful and genuinely confusing, and the common failure is stale content in production that nobody can reproduce locally because the dev server caches differently. Whatever your policy, make it explicit per route rather than inherited.
Can you use both?#
Yes, and on larger projects it is often correct — but as two deployments, not one hybrid.
Marketing and docs on Astro at the apex, the application on Next.js at app. — each optimal for its job, each deployed independently. The cost is a shared design system and two pipelines to keep alive.
Where this pays#
When marketing changes weekly and the app changes daily, coupling them means every copy tweak redeploys the application. Separating them means a content edit is a static rebuild that cannot break a login.
It also pays when the two have genuinely different risk profiles — marketing edited by several people under time pressure, the application changed carefully behind review.
Where it does not#
On a small project, two deployments is two of everything — two CI configs, two sets of environment variables, two places to look during an incident — for a site whose marketing pages number about six. Keep it in one until the split solves a problem you actually have.
What about the ecosystem?#
This is the practical difference nobody mentions in framework comparisons and it decides more projects than performance does.
Next.js has more of everything: auth libraries with first-class support, deployment adapters, examples, and answers to whatever you are stuck on at 1am. Astro is smaller and the gaps show at the edges — a niche integration you would have found ready-made elsewhere is something you write.
Astro does render React, Vue, Svelte and Solid components, so a component library is usually usable. What is less portable is anything assuming a client-side router, a React context spanning pages, or a framework-specific data layer — those assume the model Astro deliberately does not have.
How do you actually decide?#
Four questions, in order. The first two settle most projects.
- Does state need to survive navigation? A cart, a session-heavy UI, an open editor, a playing media element. Yes means Next.js.
- What proportion of the page is interactive? Mostly read means Astro. Mostly operated means Next.js.
- Is there an account area now or on the roadmap? If yes and it is real rather than aspirational, start where it will end up.
- What does the team know? All else close, the familiar one ships sooner and is maintained better.
What should not decide it: a bundle-size comparison on someone else's benchmark. Both frameworks can produce a fast page and both can produce a slow one; the deciding factor is which one makes the fast version the default for *your* page shape.
What does this site use, and why?#
Astro, static output, one client script — and it is the right call for a specific reason rather than a general one.
Every page here is read. The interactive parts are a project filter, a modal, a scroll-driven mascot and a résumé PDF generator, and each is a small piece of vanilla TypeScript rather than a component tree. There is no session, no cart, nothing to preserve across a navigation. A React runtime would render text.
The honest counterweight: the CMS is Sanity, whose Studio is React, so React is installed anyway and builds with the site. That is roughly twelve seconds of build time for a route most visitors never see — a real cost, accepted deliberately because keeping the Studio embedded is worth more than the seconds.
And a limit worth naming: if this site grew a client portal, I would not build it here. It would be a Next.js application on a subdomain, sharing tokens and nothing else — which is the two-deployment split above, arrived at honestly rather than by trying to make one tool do both.
The framework question is really a question about your pages. Answer that one and the other answers itself.
What does migrating between them involve?#
Less than a rewrite, more than a weekend, and the effort is almost entirely in the parts that were never framework-specific.
Astro to Next.js#
The usual trigger is an account area. Layouts and pages port with mechanical edits, and React components used as islands move over almost unchanged. What takes the time is everything that assumed a build step: filesystem reads, content collections, and any place the site relied on being fully static.
Next.js to Astro#
Rarer, and it is really a rewrite of the interactive layer. Server components map onto Astro components reasonably; client components with shared context do not, because the context that spanned pages has nowhere to live. Budget for redesigning that state, not porting it.
What ports for free either way#
Design tokens, CSS, content models, schema helpers, the data-fetching layer and every accessibility decision. On this site that is the large majority of the code by volume — which is the practical reason to spend your care there rather than on the framework debate.
What is the same either way?#
More than the comparison suggests, and it is where the actual quality of a site is decided.
Images, fonts and third-party scripts#
Both frameworks will happily ship a 2MB hero image, a render-blocking font from a CDN and four analytics tags. Neither protects you from the things that actually make pages slow, and those are the same problems in both.
Accessibility#
None of it is free in either framework, and all of it is cheap if you decide it once in your tokens.
Contrast, focus order, touch targets, motion preferences — no framework gives you any of it. Contrast in particular is a decision in your tokens, not in your build tool.
The content model#
Whether a heading carries a stable id, whether a category exists in one place or three, whether an editor can leave a required field blank and quietly break a page — none of that is a framework concern, and all of it decides whether the site still works in a year. Those decisions cost the same and pay the same in either tool.
The data layer#
Whether content comes from a CMS, a database or files, the fetch-and-fallback discipline is identical. A loader that degrades gracefully when the CMS is empty is the same code in both.
This is why I am reluctant to spend long on the comparison: the framework is perhaps a fifth of what determines whether the result is good. The tokens, the content model and the discipline around images matter more, and they transfer.
Conclusion#
Decide by page shape, not by benchmark. Documents that occasionally do something are Astro's case; applications that happen to have pages are Next.js's. The two frameworks are optimizing for different problems and both are good at theirs.
The single most useful test is whether state has to survive a navigation. A cart, a session-shaped UI, an open editor, a playing video — any of those and the client-side router earns its cost. None of them and you are paying for something the page never uses.
Respect the asymmetry when unsure. Next.js on a content site is a mild inefficiency you can live with; Astro on a stateful application is a structural fight that ends in rewriting the interactive core. The cheaper mistake is the safer default.
If you use both, run them as two deployments with a shared design system rather than one hybrid — and only once the split solves a problem you have, because it is two of every pipeline until then.
And keep the choice in proportion. Images, fonts, third-party scripts, contrast and the content model decide more about the finished site than the framework does, and all of them transfer. If you are at the start of a build and want the decision talked through against what you are actually making, that is a short conversation.