I built the same site in Next.js, Remix, and Astro

I built this site three times — once each in Next.js, Remix, and Astro — and served them on their own subdomains. The frameworks differed almost entirely in how they treat the server; they barely differed in what visitors received. For a content site, the deciding factor was how much JavaScript each one ships by default.

Why I built the same site three times

The honest reason: I wanted to form opinions from building, not from reading other people’s benchmark threads. A personal site is the perfect test subject — small enough to rebuild in a weekend, real enough to expose each framework’s defaults. So for a while, next.umar.codes, remix.umar.codes, and astro.umar.codes all served the same content from three different codebases.

That experiment is over, and this essay absorbs it. The subdomains now redirect here — three identical sites competing for the same search index entry turned out to be a good way to learn about frameworks and a bad way to run a website.

What differed: the server model

Each framework has a different answer to “where does your code run?”

Next.js wants to be everywhere: server components, client components, static generation, incremental regeneration — several rendering models in one framework, each with its own rules. The pages-router version of this site used exactly one of them (static generation), which meant most of the framework was surface area I carried but didn’t use.

Remix is the most opinionated: everything is a server request, loaders feed routes, forms post back. It’s the cleanest mental model of the three — and the least necessary one for a site where every page could be built once at deploy time. Running a server so that unchanging HTML can be re-rendered per request is architecture without a requirement behind it.

Astro treats pages as templates that run at build time and components as islands that only hydrate if you ask. The default is zero client JavaScript, and that default is the whole argument.

What didn’t differ

The HTML was the same. The CSS was the same. The content was identical by design. Lighthouse scores converged in the high 90s on all three once images were handled properly — for a small static site, any of these frameworks can be made fast. What differed was how much work “made fast” took: in Astro it was the default, in Next.js and Remix it was a discipline.

What the production build looks like now

The version of this site you’re reading is the Astro rebuild. The full production build is 940 KB on disk, and 608 KB of that is self-hosted fonts. It contains ten HTML pages, one CSS file, and zero JavaScript bundles — the only scripts on any page are two inline snippets (theme persistence and a toggle handler) and two JSON-LD blocks. A production build takes about three seconds on my machine.

The React versions couldn’t get near that floor, because shipping React at all costs roughly 45 KB gzipped before the first line of my own code.

Which one I’d pick, by project

Revisions

  1. First published, absorbing the retired next./remix./astro. subdomains.