Frontend hosting has to solve more than putting files somewhere public. A static export needs a CDN with sane cache headers so a new deploy is not held hostage by yesterday’s cached HTML. A client-side router needs every unknown path rewritten back to index.html instead of returning a 404 on a direct link. A server-rendered app needs an actual running process, not a bucket. Redirects, custom domains, environment variables baked in at build time, and a way back when a deploy breaks the site are the parts that separate the files being online from the site actually working. None of it is exotic engineering, but skipping any one of these is exactly the kind of thing that looks fine in a demo and breaks on the first real deploy.
This breaks down what frontend hosting needs to get right, piece by piece: the static-versus-SSR decision, caching, SPA routing, redirects and rewrites, and build-time environment variables, then narrows to what a static site specifically needs on RunxBuild.
Table of contents
- Static vs SSR is a hosting decision, not just a framework setting
- Cache headers decide whether a deploy is actually live
- SPA fallback: the 404 that only shows up on a direct link
- Redirects and rewrites, not the same thing
- Env vars at build time vs runtime
- Preview and rollback as part of hosting, not an afterthought
- How this fits the rest of the stack
- FAQ
Static vs SSR is a hosting decision, not just a framework setting
A static export is pre-built HTML and assets served straight from a CDN edge — fastest to serve, cheapest to run, and correct for content that is the same for every visitor: marketing pages, docs, a blog. Server-side rendering means a running process renders each request, which is what personalized content, per-user data, or anything that cannot be known at build time actually needs. The framework often supports both, but the hosting requirement is genuinely different: static needs storage and a CDN, SSR needs compute that stays running.
Getting this wrong in either direction shows up quickly — a static export forced to fetch personalized data client-side after the page loads, or an SSR deployment paying for a running process to render pages that never change. The Jamstack approach is the static side of this decision taken seriously.
Cache headers decide whether a deploy is actually live
Aggressive caching on an HTML document means a fresh deploy can be invisible to a returning visitor until their browser’s cache expires, which can be hours. The correct pattern splits by file type: HTML gets a short cache lifetime or no-cache so a new deploy is seen immediately, while hashed asset filenames — app.3f8a2c.js rather than app.js — get a long, immutable cache lifetime, because a content change produces a new filename rather than invalidating the old one.
This split is what makes instant cache invalidation on deploy possible without also throwing away the CDN’s actual speed advantage on assets that have not changed.
SPA fallback: the 404 that only shows up on a direct link
A client-side router handles navigation entirely in JavaScript after the initial page load, which means the server only ever needs to serve one file — index.html — for any route the app defines. This is the same rewrite-based thinking a static site CMS setup often needs for its own admin routes. The problem shows up on a direct visit or a page refresh at /dashboard/settings: the server has no file at that path, and without a rewrite rule it returns a genuine 404 instead of the app that would have rendered that route fine if reached by clicking a link inside the app.
SPA fallback fixes this by rewriting any unmatched path back to index.html, letting the client-side router take over from there. It is a one-line setting on most platforms, and its absence is the single most common “it works on my machine, breaks when a customer bookmarks a page” bug in a single-page app deployment.
Redirects and rewrites, not the same thing
A redirect changes the URL the browser shows — a 301 or 302 response sends the visitor to a different address, which is the right tool for an old URL that moved permanently and needs to keep its SEO value pointed at the new one. A rewrite serves different content at the same URL the visitor requested, invisibly, which is the right tool for something like proxying /api/* on a frontend’s own domain through to a separate backend service without the browser ever seeing a different origin.
Confusing the two produces either a URL that changes when it should not, or content served silently at a URL that should have redirected — both are usually discovered by a confused user rather than caught in testing. A site migration is the case where getting this distinction wrong costs the most: every old URL that used to rank needs an explicit redirect to its new home, and a bulk list of them is worth writing down and testing before the old URLs stop resolving at all, not discovered one broken inbound link at a time after the fact.
Env vars at build time vs runtime
A static frontend has no server to read environment variables from later, so anything referenced through process.env or similar gets baked into the JavaScript bundle at build time and shipped to every visitor’s browser, readable by anyone who opens dev tools. That is fine for a public API base URL. It is not fine for a secret, a private key, or anything that should not be visible to the public internet — those belong in a backend that reads them at request time, checked and managed from somewhere like the RunxBuild dashboard, not baked into a static frontend’s build.
The practical rule: if changing a value means rebuilding and redeploying, it is a build-time variable and it will be visible in the shipped bundle. Nothing about that is a security flaw in the hosting platform; it is a property of how static builds work, and it is worth confirming before a real secret ends up in one.
Preview and rollback as part of hosting, not an afterthought
A build that looked right in review and broke in production is not a rare event, and how fast that gets fixed depends entirely on what the hosting setup gives you afterward. A deploy log that shows exactly what changed, a history of previous deploys to compare against, and a rollback that takes seconds rather than a fresh build and redeploy are the difference between a five-minute incident and a much longer one. This is infrastructure, not a nice-to-have — it is the part of frontend hosting that only matters on the one day something goes wrong, which is exactly the day it needs to already be there.
The setups that get caught out are the ones where this was never tested until the day it was needed — a rollback button that nobody had clicked before, pointing at a deploy history that turned out to be thinner than assumed. Confirming that a rollback actually works, on a low-stakes change, before it is the only thing standing between a broken deploy and a fixed one, is worth the ten minutes it takes.
How this fits the rest of the stack
Everything above is buildable yourself with a CDN and enough configuration, and plenty of teams do exactly that. RunxBuild’s static sites handle the pieces that usually take the longest to get right: custom headers, redirects, rewrites, and SPA fallback are settings in the dashboard rather than a CDN config file you maintain by hand, with 120GB of bandwidth included and $0.10 per GB after that. The RunxBuild hosting calculator is the fastest way to see what a static frontend, plus a backend service if one is needed, actually costs side by side.
Useful related references:
- Jamstack Websites Explained
- Static Site CMS Options
- Deploy a Next.js Static Site for Free on RunxBuild
- Static Sites on RunxBuild
FAQ
Do I need SSR or is static hosting enough for my frontend?
Static hosting is correct when every visitor sees the same content built ahead of time — marketing sites, docs, blogs. Server-side rendering is needed when content is personalized per user or depends on data that cannot be known at build time. Many apps can start static and add SSR only for the pages that actually need it.
What is SPA fallback and why do I need it?
It rewrites any unmatched route back to index.html so a client-side router can handle it, instead of the server returning a 404 on a direct link or page refresh to a route like /dashboard. Without it, an app works fine navigating inside itself but breaks on any bookmarked or shared URL.
Why does my deploy not show up immediately after a fresh build?
Usually aggressive caching on the HTML document itself, rather than anything wrong with the deploy. The fix is a short or no-cache lifetime on HTML files, while hashed asset filenames get long, immutable caching, so a new deploy is visible to returning visitors right away without losing the CDN’s speed advantage on assets that have not changed.
What is the difference between a redirect and a rewrite?
A redirect changes the URL shown in the browser, which is the correct tool for a page that permanently moved and needs to keep its SEO value pointed at the new address. A rewrite serves different content at the same URL invisibly, which is correct for something like proxying an API path through the frontend’s own domain to a separate backend service.
Are environment variables safe in a static frontend build?
Only for values meant to be public. A static build has no server to read variables from later, so anything referenced in the code gets baked into the shipped JavaScript bundle and is visible to anyone who opens dev tools. Secrets belong in a backend that reads them at request time instead.