# Astro vs Next.js for a content site: numbers from building both

For a content site, Astro ships less JavaScript and Next.js wins nothing back at build time. I rebuilt both versions of this site on 2026-10-21. The Next.js 13 homepage sends 214 KB of gzipped JavaScript; the Astro 7 homepage sends 620 bytes of inline script. Cold builds took 7.6–9.9 seconds against 6.7–7.1. Astro has fewer direct dependencies, 8 against 15, but installs more packages: 481 against 258.

Published: 2026-10-21
Canonical: https://umar.codes/astro-vs-nextjs-content-site

## Revisions

- 2026-10-21 — Created from two builds of this site measured that day on Node 24.13.0: the last Next.js commit (2022-11-05; Next.js 13.0.2, React 18.2.0, Chakra UI 2.3.7) and the Astro build at master (Astro 7.3.5), plus a one-page Next.js 16.4.2 control app.
- 2026-10-21 — Published five days after its Oct 16 slot; backfilled by the publishing run because no draft existed for the row.

---

For a content site, Astro ships less JavaScript, and Next.js does not win the
difference back at build time. I rebuilt both versions of this site on
2026-10-21. The Next.js 13 build sends 214 KB of gzipped JavaScript to its
homepage. The Astro 7 build sends 620 bytes of inline script. Cold builds took
about the same time.

## How I measured the two builds of this site

This site ran on Next.js until 2026-07-27, when I [converted it to
Astro](/next-to-astro-conversion). Both versions are still in the repository, so
I checked each one out into its own git worktree and built it on the same
machine, an Apple M4 Pro on Node 24.13.0.

- **Next.js:** the last commit before the conversion, from 2022-11-05. Next.js
  13.0.2 on the pages router, React 18.2.0, Chakra UI 2.3.7 with Emotion 11.10.0
  and framer-motion 7.2.0. I installed from its own `yarn.lock` with yarn
  1.22.22. It builds today without changes.
- **Astro:** the current production build, Astro 7.3.5 with MDX, installed from
  its `pnpm-lock.yaml`.

Every gzip figure is `gzip -9` over the files a browser loads. I left out the
Next.js `noModule` polyfill script, because modern browsers do not fetch it.

The two sites do not have the same content. The 2022 site had 17 routes, most
of them agency pages and blog posts. The 2026 site has 62 pages. So these
numbers compare what each build ships per page, not two copies of one page. The
[three-frameworks essay](/three-frameworks) covers the experiment where the
content was identical; this page adds the measurements.

## JavaScript per page: 214 KB against zero

| Page | Next.js 13, raw | Next.js 13, gzip | Astro 7 |
|---|---|---|---|
| Homepage | 648,819 bytes | 214,033 bytes | 620 bytes inline, 0 files |
| One blog post | 627,054 bytes | 205,947 bytes | 620 bytes inline, 0 files |
| 404 page | 493,341 bytes | 160,604 bytes | 620 bytes inline, 0 files |

The Astro `dist/` folder contains no `.js` file at all. The 620 bytes are two
inline scripts on every page: one keeps the theme choice and one handles the
toggle. The JSON-LD blocks are scripts too, but no browser executes them, so I
did not count them.

The Next.js 404 page is the floor, because it has almost no code of its own.
Its 160,604 gzipped bytes come in four files:

| File | Gzipped | What it holds |
|---|---|---|
| `framework` | 45,391 bytes | React and React DOM |
| `main` | 26,281 bytes | The Next.js client runtime and router |
| `webpack` | 1,045 bytes | The chunk loader |
| `_app` | 87,887 bytes | Chakra UI, Emotion, framer-motion and my layout |

The 45 KB React figure is the one the three-frameworks essay quotes. Every page
pays all four files before its own code loads.

## Is a 2022 Next.js build fair to Next.js today?

Partly. Most of the 2022 floor was my choice of UI kit: the `_app` file is 55%
of it. A Next.js site without Chakra pays only the first three files, 72,717
gzipped bytes.

To check whether that floor got smaller, I built a control app with Next.js
16.4.2 and React 19.3.1: the app router, one static page, and no client
components. That page loads five scripts, 455,990 bytes raw and 134,910 bytes
gzipped, plus 3,638 bytes of inline payload. The current framework floor is
larger than the 2022 one, not smaller. Server components remove my components'
code from the bundle, but the runtime that hydrates the page still loads.

## HTML and CSS: where each build puts the styles

The Next.js homepage HTML is 152,521 bytes, or 23,917 gzipped. Of that,
92,165 bytes are 109 inline `<style>` tags that Emotion writes during server
rendering. Each page carries its own copy of the styles it uses.

The Astro homepage HTML is 12,525 bytes, or 4,109 gzipped. All 62 pages share
one stylesheet of 7,571 bytes, or 2,157 gzipped, which the browser caches after
the first page.

## Build time is about the same

| Build | Pages | Cold build times |
|---|---|---|
| Next.js 13, `next build` | 17 routes | 7.57 s, 9.12 s, 9.89 s |
| Astro 7, `astro build` | 62 pages | 7.09 s, 6.77 s, 6.66 s |

`next build` includes linting and type checking. `astro build` does neither,
and with `astro check` before it the Astro total is 10.50 seconds. The Astro
build also renders a 1,200 × 630 Open Graph image for each of the 62 pages with
satori. A warm Next.js build, with its cache kept, took 3.74 seconds.

Per page, Astro builds faster. Per build, the times are close enough that I
would not choose a framework on them.

## Dependency counts: fewer direct, more installed

| Count | Next.js 13 | Astro 7 |
|---|---|---|
| Direct runtime dependencies | 15 | 8 |
| Packages in the production tree | 258 | 481 |

The Astro site declares fewer dependencies and installs nearly twice as many
production packages. Astro brings its whole build toolchain into the production
tree: Vite, esbuild, sharp for images and Shiki for code. Next.js 13 ships its
compiler as one native binary, so its tree counts fewer packages. None of those
packages reach the browser in either build. A dependency count measures what
you install, not what you ship.

## Which one I would use for a content site

For a site where every page is a document, I use Astro. Its default is zero
client JavaScript, and on this site that default held across 62 pages without
any effort from me. In Next.js, my 2022 floor was 160 KB gzipped with a UI
kit, and today's floor is 135 KB without one. That cost comes before any
component of my own.

I would use Next.js when the pages are an application: sessions, forms, and
state that changes after load. There, the runtime does work that you would
otherwise write yourself. The reasons behind the choice are in the
[three-frameworks essay](/three-frameworks), and the conversion itself is in
[the plan that moved this site to Astro](/next-to-astro-conversion).
