An HTML-first rewrite doubled their users. The JS framework wasn't the bottleneck — it was the tax.

5 min read 1 source clear_take
├── "HTML-first beats JS frameworks for content sites because the default stack is silently losing measurable users"
│  ├── Mo Kohn (mohkohn.co.uk) → read

Kohn rebuilt his personal site from a JS-framework SPA to server-rendered HTML with no build step and reports user numbers roughly doubled overnight. He argues the same content and URLs shipped as HTML instead of a JS payload made the difference, exposing how much audience the SPA shell was costing him before the page ever rendered.

│  └── @edent (Hacker News, 267 pts) → view

Submitted the post to HN where it drew 267 points, signaling that the developer community recognized the pattern. The framing — 'doubled our users overnight' — resonated as evidence that the JS-framework default is broken for content sites.

├── "Analytics dashboards hide the real cost of SPAs through survivorship bias"
│  └── top10.dev editorial (top10.dev) → read below

Argues that users who bounce before the SPA shell loads never fire a pageview event, so they appear as nothing in Google Analytics. This means teams running JS-framework content sites are systematically blind to the audience they're losing, and Kohn's doubling is the visible portion of a much larger hidden cost.

└── "React still has a legitimate place — HTML-first isn't universal"
  └── top10.dev editorial (top10.dev) → read below

Acknowledges the HN counterpoints that JS frameworks remain appropriate for genuinely interactive applications. The argument is narrower than 'React is bad' — it's that content sites (blogs, docs, marketing, news) are the wrong place to pay the SPA tax, not that the tax is never worth paying.

What happened

Mo Kohn, an indie developer, rebuilt his personal site from a JavaScript-framework SPA to plain HTML with progressively-enhanced CSS and a sprinkle of vanilla JS. The writeup landed on Hacker News with 267 points and the kind of comment thread that only happens when the room collectively recognizes something they've been ignoring. The headline claim: user numbers roughly doubled overnight after the switch.

The site went from a JS-framework SPA — bundler, hydration, client-side routing, the full kit — to server-rendered HTML files with no build step at all. No React. No Next. No Astro. Just files. CSS handles layout and theming. A tiny bit of JavaScript enhances specific interactive elements, but nothing depends on it loading or running. Open the page, see the page. The whole thing is small enough that the entire site downloads faster than most React apps download their framework chunk.

The traffic doubling wasn't from SEO improvements taking weeks to compound or a viral post. Kohn reports it was effectively immediate — the same content, the same URLs, just shipped as HTML instead of as a JS payload that renders HTML.

Why it matters

The interesting thing isn't that HTML is faster than React. Everyone knows that. The interesting thing is the size of the gap, and where it actually shows up.

For content sites — blogs, docs, marketing pages, news — the default stack in 2026 is still a JS framework, and that default is silently costing measurable users. Not 5%. Not 10%. In Kohn's case, roughly half his potential audience was bouncing before the page rendered. That's the number that should make you uncomfortable, because your analytics dashboard doesn't show you the users who left before the SPA shell loaded. They show up as nothing. No pageview event, no session, no funnel entry. Survivorship bias, served daily via Google Analytics.

The HN thread surfaced the usual counterpoints, and they're worth taking seriously. Yes, React has a place — in apps with persistent state, complex interaction, real-time updates, anything that genuinely benefits from a client-side runtime. Yes, modern meta-frameworks like Next, Remix, and Astro have largely solved the SSR-and-hydration story for the framework-curious. Yes, edge rendering and streaming HTML close some of the gap.

But none of that addresses the actual finding. The cost isn't React-the-library. The cost is the cumulative tax of the framework ecosystem: the bundle, the hydration cycle, the client-side router intercepting clicks, the runtime checking what changed, the analytics scripts that the framework's tutorial told you to add, the polyfills, the CSS-in-JS runtime, the icon libraries shipped as components instead of SVG. Each one is defensible in isolation. Together they're a 2-second delay on a $200 Android phone on a hotel wifi, and that 2-second delay is the doubling.

The benchmark that matters isn't Lighthouse on your M3 MacBook over fiber — it's Time to Interactive on a mid-tier Android device on a saturated cell tower, because that's what most of the planet uses. Kohn's piece is a reminder that the gap between those two contexts has been widening, not narrowing, because framework tooling has gotten more sophisticated while phones in the median user's pocket have not.

There's a separate craft argument the HN thread kept circling. HTML degrades gracefully. JS does not. An HTML site with broken CSS is ugly but readable. A JS site with a broken bundle is a white screen. The failure modes are categorically different, and one of them costs you users while the other costs you taste points.

What this means for your stack

Nobody is suggesting you rip out Next from your e-commerce checkout flow. The question is narrower: for the specific pages you ship that are mostly text, do you actually need a runtime?

Audit your own site: open it on a throttled connection in DevTools and watch what loads before the user sees content. If the answer involves more than the HTML and the CSS, you're paying a tax you might not be collecting value on. Run the same test on a real cheap Android phone if you have one, because emulation flatters you.

The practical move for content-heavy properties is to draw the line earlier. Static HTML for everything that can be static. Islands of interactivity (Astro's actual selling point, Fresh's, htmx's whole philosophy) for the bits that need it. Server-rendered HTML with progressive enhancement for forms, search, and account states. Reserve the full SPA pattern for the surfaces where state really is client-owned — editors, dashboards, design tools, anything where the URL doesn't capture the relevant state.

The other practical move is to stop optimizing the wrong axis. Frontend engineering culture has spent a decade getting better at hydration, partial hydration, selective hydration, resumability, and various spellings of "actually you don't need to ship as much JS as you thought." Each is an improvement. None of them beats not shipping the framework in the first place when you didn't need it.

For teams: this is also a hiring and complexity argument. An HTML-first site is debuggable by anyone who knows HTML. A modern React site requires knowing React, the meta-framework, the bundler, the styling system, the data-fetching layer, and the deploy target's specific quirks. Complexity isn't free. It compounds in onboarding time, in the number of people who can fix a Friday-night production issue, and in the years of dependency churn you sign up for.

Looking ahead

The pendulum visibly moved in 2024-2025 and is still moving — htmx made it into enterprise talks, Astro became the default for content sites among people who used to default to Next, and "the web platform is enough" stopped being a contrarian take. Kohn's post is a single data point, but it's a data point in a direction the industry has been quietly drifting toward for a while. The framework era isn't ending. The reflex to reach for a framework when you don't need one might be. If you ship a content site, the cheapest user-acquisition move available to you in the next quarter might be deleting your build step.

Hacker News 1206 pts 539 comments

Building an HTML-first site doubled our users overnight

→ read on Hacker News

// share this

// get daily digest

Top 10 dev stories every morning at 8am UTC. AI-curated. Retro terminal HTML email.