Engineering
Why we ship static HTML when we can
A framework is a tool for managing complexity. If the complexity is not there, the framework is pure cost — paid by whoever loads the page.
The cost lands on the visitor
A modern JavaScript framework will happily ship several hundred kilobytes of runtime before your first sentence renders. On a fast laptop over fibre, nobody notices. On a mid-range Android phone over a congested mobile network — which is how a large share of our region browses — that difference is felt directly, and it shows up as people leaving.
This very site is three files and roughly fifteen kilobytes compressed. It renders before a framework bundle would have finished downloading.
Ask what the page actually does
The honest test is whether the page holds meaningful client state. A marketing site, a documentation page, a brochure, a landing page — these display content and collect the occasional form. HTML and a little CSS do that natively, and have for decades.
A dashboard with live filters, an editor with undo, a chat interface — these genuinely benefit from a component model and a rendering framework. Use one there. The mistake is applying the dashboard toolchain to the brochure.
What you give up, honestly
Static HTML is not free of trade-offs, and pretending otherwise is how people end up regretting the choice:
- No component reuse across pages. Repeated markup like a header has to be duplicated or generated by a small build step.
- No type checking. Nothing tells you a class name is misspelled except looking at it.
- Content updates mean editing HTML, which is fine for a developer and unpleasant for anyone else. Past a certain page count you want a CMS or a generator.
Our rule of thumb: below roughly a dozen pages with content that changes rarely, hand-written static wins. Above that, reach for a static site generator — you keep the fast output and get the reuse back.
The platform got good
Much of what pulled people toward frameworks is now built in. CSS grid and flexbox handle layout. Custom properties give you real design tokens and theming. <details> is an accessible accordion with no JavaScript. IntersectionObserver covers scroll effects in a few lines. Container queries and :has() close most of what remained.
None of this is an argument against frameworks. It is an argument for choosing deliberately, because the default choice is rarely free and the person paying for it is not on your team.
Want a second opinion on an architecture decision? We are happy to help.