Kohn rebuilt his SPA as pre-rendered HTML and saw daily active users roughly double within 24 hours. He attributes the gain not to better UX but to Googlebot and LLM crawlers finally being able to index content that was previously locked behind client-side JavaScript execution.
Submitted the post to HN where it hit 1,118 points, signaling broad agreement with the thesis. The submission's traction reflects engineers recognizing the pattern from their own sites.
Argues that while Googlebot does render JS, it does so on a second pass with a queue, a budget, and a tolerance for failure that drops as bundles bloat. Kohn's clean before/after is positioned as a data point in a debate that has been mostly anecdotal since 2015.
Multiple commenters in the thread describe shipping React/Next/SvelteKit sites with SSR enabled and still watching indexing degrade. They point to hydration mismatches, late-loading metadata, and JS-injected canonical tags as quiet saboteurs of pages that look server-rendered on inspection.
The thread reads like a support group, with comment after comment describing the same arc — shipped a framework site, watched indexing degrade, blamed Google, then noticed view-source showed only an empty root div. The volume of identical stories suggests this is a systemic issue rather than a niche misconfiguration.
Mo Kohn, a UK-based engineer, published a post-mortem titled "Building an HTML-first site doubled our users overnight" that hit 1,118 points on Hacker News. The thesis is brutally simple: he ripped the JavaScript framework off his content site, served pre-rendered HTML, and watched daily active users roughly double inside 24 hours. No A/B test theatrics, no funnel optimization — just less code.
The original site was a fairly standard SPA: client-side routing, hydration, the usual suspects. Content was real and the design was fine, but the initial payload required JavaScript to execute before anything readable appeared in the DOM. Kohn's rebuild inverts that: HTML is the source of truth, JS is sprinkled on top only where it earns its keep. The doubling didn't come from humans loving the new site more — it came from crawlers, both Google's and the new wave of LLM scrapers, finally being able to read it.
The HN thread reads like a support group. Comment after comment from engineers describing the same arc: shipped a React or Next or SvelteKit site, watched indexing degrade, blamed Google, eventually noticed that `view-source` showed a `
` and not much else. Several commenters pointed out that even with SSR turned on, hydration mismatches, late-loading metadata, and JS-injected canonical tags quietly sabotage what looks like a perfectly server-rendered page.
The SEO-versus-SPA debate has been running since roughly 2015, and the official line from Google has long been "we render JavaScript, you'll be fine." In practice, anyone who has watched Search Console knows the truth is messier. Googlebot does render JS, but on a second pass, with a queue, with a budget, and with a tolerance for failure that drops every time your bundle bloats. Kohn's experience is a clean data point in a debate that's been mostly anecdotal.
The bigger shift, though, is the LLM crawler. GPTBot, ClaudeBot, PerplexityBot, Google-Extended, Applebot-Extended — none of them execute JavaScript with anything close to a real browser's fidelity. If your content lives behind a hydration step, you are invisible to the systems that increasingly mediate how developers discover tools, libraries, and writing. The traffic Kohn doubled almost certainly wasn't just Google organic; it was the long tail of AI-mediated discovery that quietly became material in the last 18 months.
There's a performance angle too, but it's downstream. A 50KB HTML document with inline critical CSS hits LCP before a 400KB JS bundle has finished parsing. Core Web Vitals improve, which feeds back into ranking, which feeds back into traffic. Compounding effects from a single architectural choice. Compare this to the SSR-with-hydration approach that frameworks like Next.js, Remix, and SvelteKit sell: it solves the first-paint problem but still ships the framework runtime, still pays the hydration cost, still risks the mismatch class of bugs.
The counter-argument, raised forcefully in the HN thread, is that not every site is a content site. A dashboard, a design tool, a real-time collaboration app — these are not reading material, and HTML-first is the wrong frame. Fair. But the number of sites that pretend to be apps when they are, in fact, articles with a comment box is enormous. The honest question to ask of your codebase is whether the JavaScript is doing work the user can perceive, or work the framework demands.
If you run a marketing site, docs, a blog, a directory, or any content-led product, the practical takeaway is to audit what `curl -s yoursite.com | grep -c "actual content phrase"` returns. If the answer is zero, you have a problem that no amount of structured data or sitemap submission will fix. The fix isn't necessarily "delete your framework." It's to make HTML the canonical artifact and treat JS as progressive enhancement.
Concretely: static site generators (Astro, Eleventy, Hugo) ship effectively zero JS by default and let you opt in to islands of interactivity. Next.js and SvelteKit can be configured to output mostly static HTML if you stop reaching for client components. If you're on a pure SPA today, the migration path is usually "add a static export step" before "rewrite everything" — most frameworks have one. For genuinely interactive surfaces, HTMX and Alpine give you 80% of the dynamic UX with 5% of the runtime, and the HTML stays readable to crawlers throughout.
The diagnostic worth running this week: fetch your top ten pages with `curl` and no JS execution, then ask whether a reasonable language model could summarize each. If it can't, neither can ChatGPT, Claude, or Perplexity when a user asks them about your space. That's the new SEO, and it's already eating into the old one.
The pendulum has been swinging back toward the server for a few years — React Server Components, Phoenix LiveView, Rails 7's Hotwire, the entire htmx movement. Kohn's traffic doubling is a useful receipt for an argument that was already winning on the merits. Expect the next 12 months to make "what does your site look like to a crawler that can't run JS" a first-class concern, not an SEO afterthought, because that crawler is now also the discovery layer for every AI assistant your users talk to. The frameworks that win this cycle will be the ones that treat HTML as the product and JavaScript as the optional upgrade.
I haven't heard much about in a while, but the HTML Triptych proposal [0] is still something I hope to eventually land in browsers. HTML forms speaking to REST endpoints are a good pattern. (meaning user-aiding validation is handled via the input attributes, real validation is handled on the fa
Most of my apps are now simply HTMX + Go + SQLite.I've found it's enough for most projects.One of my sites is image heavy and serves 10 TB of traffic per month. For this, I use the following setup:1. S3 (I wanted reliable data storage) 2. In front of it, I have Cloudflare (with Tiered Cach
Excellent article but I am always torn when I read inspirational articles like this - it makes perfect sense to me and I love the idea of simple, non-nonsense sites that work well, load quickly and don't rely on the latest browsers to function.Then I start to wonder if that's just because
The counterargument: In Defence of the Single Page Application:https://williamkennedy.ninja/javascript/2022/05/03/in-defenc...
Top 10 dev stories every morning at 8am UTC. AI-curated. Retro terminal HTML email.
As a non-web dev, I have a question about this part:> There was a sad coda; as is the way of contract work, I moved on. I explained what I had built to my replacement, that it always worked even without javascript. He was appalled and said, “but that’s a lot more work for us.”Why is it more work?