Static HTML still wins the boring races
There is a version of every web project where the answer is a folder of HTML files on a CDN, and a version where it is not. The interesting question is not which is fashionable but which failure modes you are choosing.
What a CDN can do with a plain file
A static file has a property that almost nothing else in a web stack has: it is identical for every request. That single fact is what makes the rest of the delivery chain simple. The file can be copied to every edge location ahead of time. It can be held in memory. It can be served while the origin is down, on a stale-while-revalidate policy, without anyone noticing. It can be compressed once at deploy time with a slow, thorough algorithm instead of quickly on every request.
None of that requires configuration beyond a correct Cache-Control
header. The work has already been done by the time a visitor arrives, which is
why the p99 response time for a static asset is usually within a few
milliseconds of the p50. There is no cold start, no connection pool, no query
that occasionally hits an unindexed column.
The two headers that do all the work
Almost every caching problem on a small site comes down to giving documents and assets the same policy. They want opposite ones.
Assets whose filename contains a content hash can be cached forever, because a change to the file produces a change to the URL:
Cache-Control: public, max-age=31536000, immutable
HTML documents cannot, because the URL stays the same while the content changes. What you usually want is for the browser to revalidate every time while the CDN keeps serving instantly:
Cache-Control: public, max-age=0, must-revalidate
Get those two right and a static site is effectively finished. Get them backwards and you will spend an afternoon wondering why a deployment appears to have done nothing.
Where it stops being enough
Static files stop being sufficient the moment output depends on the request. Personalised content, anything behind a login, anything that has to be correct within seconds rather than within a deployment - these are genuinely dynamic and pretending otherwise produces worse systems, not simpler ones.
The mistake is treating that as an all-or-nothing decision. This site is static
except for four functions under /api, and those exist only because
their output genuinely differs per request: the serving region, the request
headers, the response to a form. Everything else is a file. The dynamic surface
is small enough to reason about in one sitting, which is the actual goal.
What you give up
Honesty requires listing the costs. Hand-written static HTML means duplicated markup - the header and footer on this page exist, character for character, in every other page in the repository. Change the navigation and you change it five times. At around a dozen pages that stops being tolerable and you want a generator.
You also give up content that changes without a deployment. If a non-technical person needs to publish, a folder of files is the wrong answer regardless of how fast it serves.
For a site whose entire purpose is to be a fixed, verifiable target, neither cost applies. That is the whole argument: not that static is better, but that it is better here, and knowing why is the difference between a choice and a habit.
The test
If you want to know whether your site is really static, fetch it the way a crawler would and count the content:
curl -s https://usharea.in/ | grep -c "pipeline works"
If that returns zero, the page is assembled in the browser and everything in this note applies to something other than what you are shipping.