Skip to content

Stack choices

HTMX vs React for small SaaS products: a developer's honest take

Published Lefty Software LLC

HTMX vs React for small SaaS products is a question I can answer without hedging, because I ship on both sides of it and have stopped pretending the answer is mysterious. Every product I've built lately — the scheduling SaaS CourtWiz, the stringing-business platform StringBench, and this very website — runs on server-rendered Go and HTMX. That is not a contrarian identity. It is a scoping decision: for a small team building a CRUD-shaped product, HTMX deletes an entire category of work, and I'll show you exactly where it wins, where it bites back, and when I still reach for React.

What HTMX actually is

HTMX is a small JavaScript library that lets plain HTML trigger requests and swap the responses into the page. The version served by this site is about 17 kB gzipped. A button with hx-post="/invite" sends a form post; the server responds with an HTML fragment; HTMX swaps it in. Navigation gets the same treatment through hx-boost, which intercepts link clicks and swaps just the page body. That's the whole mental model: the server is still a server, the responses are still HTML, and there is no client-side application state to synchronize, hydrate, or debug.

React, by contrast, moves the application into the browser: components render from state, the state lives in JavaScript, and the server becomes an API that ships JSON. That is a genuinely powerful model — for products whose complexity lives in the client. The whole HTMX-vs-React question is really "where does this product's complexity live?"

Where HTMX wins for a small SaaS

One language, one artifact, one deploy

There is no separate API layer to design, version, and keep in sync with a client, no duplicated validation rules in two languages, no bundler pipeline, no npm audit Friday. This site compiles to a single Go binary with every template, style, and script embedded, built FROM scratch — an image with no shell, no package manager, and almost no attack surface. CourtWiz and StringBench deploy the same way. The operational simplicity compounds: fewer moving parts is a feature your customers never praise and always benefit from.

The server stays the source of truth

In an SPA, the browser holds a copy of your data and eventually disagrees with the server about it. Every HTMX app I've built simply doesn't have that bug class: the page shows what the server returned, last request wins, and "stale cache" stops being a support ticket category. For a small product, that is not an architectural preference — it is weeks of edge cases you never write.

Performance you get by accident

In this build, the homepage HTML is about 37 kB uncompressed and 7 kB with Brotli. Those figures exclude fonts, stylesheets, images, and scripts. There is no hydration pass, no framework runtime to parse before pixels appear. Images render crisply, navigation feels instant because only the body swaps, and Core Web Vitals mostly take care of themselves. I did not get there by profiling heroically; I got there by not shipping a JavaScript framework to people who wanted to read a paragraph.

A stricter security posture

Because HTMX apps ship almost no first-party JavaScript, a strict Content-Security-Policy is easy to keep honest. This site runs CSP with no 'unsafe-inline' allowance for scripts at all — the one inline script, a theme bootstrap, is hash-pinned — and there was no moment where a framework's runtime demands forced an exception. Less JavaScript is not just payload; it is fewer supply-chain names on the audit list.

Where React clearly wins

Now the other side, because the honest answer requires it. React earns its complexity when the product is a rich client:

  • Documents, canvases, spreadsheets, editors — anything where sub-second local interaction on mutable state is the product.
  • Offline-first behavior and aggressive optimistic updates.
  • Teams already fluent in React, with component libraries and hiring pipelines built on it.
  • Codebases sharing real logic with a React Native mobile app.
  • Long-lived products investing in a design system with thousands of storybook hours behind it.

If two of those describe your product, build it in React and don't look back. The mistake is applying that answer to every product by default — most small SaaS products are forms, lists, dashboards, and workflows, and for those, React's superpowers are mostly superfluous.

The trade-offs nobody puts in the README

HTMX is not free money. Here is what it actually costs, from shipping it in production:

  • Every interaction is a round trip. Click, request, respond, swap. On a fast server and CDN that feels instant — until a customer is on a train. Latency-sensitive micro-interactions (drag, typeahead-as-you-pause, optimistic saves) are where HTMX fights you hardest.
  • Fragments need discipline. You end up designing server endpoints around HTML partials, and out-of-band swaps (updating a badge outside the main target) get fiddly if your templates aren't organized for them.
  • The back button will bite you once. Mine did: with boosted navigation, a history restore must receive a full document, not a fragment — return a fragment there and the restored page loses its navigation chrome. It's a known bug class, it's guardable in one place (mine now is), but you will meet it personally.
  • A smaller ecosystem. Fewer off-the-shelf widgets, fewer Stack Overflow answers, fewer candidates who know it. You will write more server-side templates than a React shop writes components.
  • Live updates are a design decision. Polling, SSE, or websockets — HTMX doesn't choose for you, and "it depends" is the only honest default.

How I actually decide

My default for a small SaaS or internal tool is server-rendered HTML with HTMX, and I treat React as the targeted upgrade it is: reach for it when interaction complexity genuinely lives in the client, when the team's fluency is there, or when offline behavior is a requirement rather than a wish list item. Hybrid approaches — a mostly-HTMX app with one rich island — work, but every island adds a seam, and seams are where small projects go to die. Choose one model for v1.

Who maintains it later matters as much as what ships now. HTMX's server-centric model ages well for a solo developer or a small team, because the whole system lives in one codebase you can read end to end. Hand a three-person startup a React SPA plus its API and you have handed them two codebases and a contract between them that they must now keep.

StringBench is a good example of the default in production: a working stringer's business platform — customers, rackets, and string inventory tracked down to half-reel precision, with auto-generated QR-coded job labels — running Go and HTMX under a real workload, not a demo workload.

StringBench, a racquet stringing business platform built with Go and HTMX, shown on desktop and mobile: customer, racket, and string inventory tracking with QR-coded job labels
StringBench: inventory to the half-reel, QR job labels, no SPA in sight.

One last reframe: for a small product, the stack is rarely what decides success — scope is. A focused v1 built with a boring stack beats an ambitious one built with a fashionable one, every time. That is a money question as much as a technical one, so I've written up what a custom web app actually costs in 2026. Both products above are live if you want to click around — you'll find them in my portfolio.

Want a real number for your idea?

Tell me what you're trying to build. I'll reply with a written scope and a fixed price — not a sales call.

Get in touch

← More from the blog