Measured in your browserWe advise on speed. We practice it.Loaded just now · real numbers from this visit, not a lab score.
Page loaded
First byte
DOM ready
First paint
Largest paint
DNS lookup
TLS handshake
Transferred
Saved by compression
Requests

A single-page app is the easiest thing a CDN ever serves and the easiest to serve subtly wrong: hashed bundles that could cache forever behind an index.html that must not, client routes that 404 on refresh, and deploys that strand users on missing chunks. Four rules fix all of it permanently.

Rule 1: hashed assets are immutable

Every modern build pipeline emits content-hashed filenames — app.3f9c2b.js — which means the file at that URL can never change, only be replaced by a differently-named successor. Tell the whole chain exactly that: Cache-Control: public, max-age=31536000, immutable on all hashed output. Browsers skip revalidation entirely, the edge serves from cache indefinitely, and your hit ratio on the app's bulk approaches total. The only mistake available here is timidity — short TTLs on hashed assets buy zero safety (the content cannot change) and cost revalidation traffic forever. If any assets ship unhashed (some public files, legacy vendor scripts), either bring them into the hashing or give them the modest TTLs their mutability demands; never let one policy cover both classes.

Rule 2: index.html is the freshness point

The entire app's updateability now concentrates in one small file: index.html, whose script tags name the current hashes. It must be fresh — no-cache (which permits storage but forces revalidation) at the browser, and at the edge either bypass or a deliberately short TTL with purge-on-deploy. With ETags on, revalidating this file costs a 304 and single-digit milliseconds, so freshness here is nearly free while staleness is expensive: a cached old index references bundles you are about to delete. This asymmetry — one tiny always-fresh file fronting an immutable everything-else — is the whole architecture; every SPA delivery bug is a violation of one side of it.

Rule 3: every route serves the shell

History-mode routing means /settings/profile exists in the client router but not on any server, so a refresh or deep link there returns 404 unless the edge is told otherwise. Configure the SPA fallback: any path that does not match a real file rewrites to /index.html (with a 200, not a redirect). Every CDN and static host has a native mechanism — rewrite rules, error-page overrides, or an explicit SPA toggle. Two guardrails keep the fallback honest: scope it so asset paths are excluded (a missing chunk must surface as a real 404 to your monitoring, not silently return HTML — the misconfiguration that produces "Unexpected token <" in consoles everywhere), and return real 404s for known-dead namespaces if SEO or correctness cares about status codes.

Rule 4: deploy assets first, index last

Deploys strand users when ordering is wrong: publish a new index before its bundles exist and every visitor in that window fetches 404s; delete old bundles while an old index (or an open browser tab) still references them and navigation breaks mid-session. The safe sequence is mechanical — upload new hashed assets, verify them at the edge, then publish the new index and purge only that; and keep the previous deploy's assets available for a retention window (a day covers reloads; a week covers long-lived tabs) rather than deleting at cutover. Add a version check in the app that prompts or soft-reloads long-lived sessions on skew, and chunk-load errors disappear from your error tracker for good.

APIs and the rest of the estate

The app's API calls follow their own discipline — pass-through by default, micro-caching only for genuinely shared responses — which is the API guide's territory; the delivery win for SPAs is simply ensuring API paths are cleanly separated (a dedicated subdomain or path prefix with its own rules) so app-shell policies never bleed onto them. If you deploy on an integrated static platform, these four rules are largely preconfigured — the value of knowing them is recognizing when a custom CDN setup, a proxy in the middle, or a teammate's "optimization" has broken one. When the app grows server-side rendering, revisit with fresh eyes: SSR HTML is tier-2 content with personalization rules, and the pure-SPA shortcuts stop applying.

Get the free assessmentMore analysis