On this page
A product homepage, an inventory page, and an authenticated reporting screen should not automatically share one rendering strategy. Their data changes at different rates, their audiences differ, and their failure modes carry different consequences. Treat rendering as a route-level decision about when work happens and what readers can see while that work completes.
Establish freshness and latency requirements
Begin with a route inventory. For each page, record whether its content is public, how stale it may become, whether it needs user-specific data, and what should happen when an upstream dependency fails. Ask product owners for observable requirements: a price must be checked before purchase, while a tutorial correction might tolerate a short publishing delay.
Use the API Latency Tester to examine a public endpoint that a candidate page depends on. Compare several requests rather than trusting one result. The measurement describes that request path and testing location; it does not predict database time inside your production server or the latency every visitor will experience. Never paste private tokens into a public testing workflow.
Keep a freshness budget beside the latency observations. A fast response containing unacceptable stale data is not a success. A request-time page that waits on several slow services may also miss the product requirement even though every value is current. Rendering choices should balance both dimensions explicitly.
Understand the four models without false oppositions
Server-side rendering, or SSR, generates page HTML during a request. It is useful when the response depends on current request information or data that should not wait for a build. The cost is that server execution and required dependencies can contribute to response time. Shared response caching may change this behavior, so request-time rendering and cache policy must be considered separately.
Static site generation, or SSG, produces HTML ahead of requests, commonly during a build. Readers can receive already-created pages without executing the page renderer for each visit. Updates generally require another publishing operation unless the framework provides an additional regeneration mechanism. Large route sets and slow content sources can make build workflows important architectural constraints.
Incremental static regeneration, or ISR, is a framework-supported approach to updating generated output without rebuilding every page. Policies may be time-based or explicitly triggered. Exact behavior varies: a stale page may be served while regeneration runs, and a configured interval is not necessarily a guarantee that content refreshes at that exact moment.
A single-page application, or SPA, typically loads an application shell and uses browser JavaScript to render views and request data. Its client-side routing model is a different axis from HTML generation: an SSR application can also use SPA-like navigation after the first load. Avoid treating these labels as four mutually exclusive product categories.
The web.dev rendering guide provides a useful conceptual overview. For implementation, use your framework's terminology and version-specific rules rather than assuming every platform implements these models identically.
Match route behavior to the simplest model
Choose SSG for stable public documents when build and publication workflows can satisfy the freshness requirement. Documentation, policy explanations, and evergreen landing pages often fit. Do not assume a page needs request-time rendering merely because it contains one interactive calculator; that widget can hydrate independently or fetch its own public data.
Choose SSR when the initial response genuinely depends on request context or current server data. An account page may need the signed-in user's information before rendering. However, private content requires cache isolation: never place a personalized response into a public shared cache just because another route benefits from caching.
Choose ISR-style output when public pages need updates more frequently than whole-site builds allow, but brief staleness is acceptable. Product descriptions and editorial archives can fit this pattern. Time-sensitive inventory should still be verified at the transactional boundary rather than treated as authoritative because it appeared in generated HTML.
Choose a client-rendered SPA when the main experience is an interactive application and an initial data-loading phase is acceptable. Internal tools can fit well, particularly when a static shell connects to a separately managed API. Authentication and authorization still belong on the backend; hiding a route in the client provides no access protection.
For sites with a separate content service, our headless architecture guide helps separate data ownership from rendering decisions. One backend can support several route strategies without forcing every frontend screen into the same lifecycle.
Implement a small, explicit route policy
Avoid scattering unexplained rendering settings across the repository. Maintain a short policy describing each route family and its update trigger. The following example illustrates Astro's distinction between prerendered and request-rendered pages; request rendering requires a compatible server adapter and deployment configuration.
---
// src/pages/account.astro
export const prerender = false;
const user = Astro.locals.user;
if (!user) {
return Astro.redirect('/login');
}
---
<h1>Your account</h1>
<p>Signed in as {user.displayName}</p>Here, middleware is assumed to establish a trusted session in locals. The example is not a complete authentication system. Protected data helpers must still enforce access, and the host must not publicly cache personalized HTML. See the Astro on-demand rendering documentation for configuration requirements.
For Next.js applications, consult the official documentation before adopting regeneration settings. Runtime mode, framework version, and hosting capabilities affect the available behavior. A static export cannot execute request-time account logic simply because the same source tree contains server-capable components.
Test updates, navigation, and failures
Verify the update lifecycle with a real content change. Publish a correction, request the page immediately, request it again after the expected refresh window, and check a second region or browser where possible. For triggered regeneration, test webhook failure and retries rather than assuming every update notification arrives once.
Then simulate upstream failure. Does SSR return a useful error state? Does regeneration preserve previously valid output? Does a client-rendered page retain its navigation and explain that data could not load? These behaviors vary by implementation, so write acceptance tests for the intended outcome.
Check direct navigation separately from in-app navigation. A route may work when reached through a hydrated shell but fail on reload because the host lacks fallback routing. Conversely, an initial HTML response may be correct while later client navigation retains stale state. The responsive testing guide offers a useful testing mindset beyond one desktop browser.
Finally, review the strategy after features change. Adding personalization to a formerly public page can invalidate its caching assumptions. Related framework articles can support implementation, but the route's data contract should remain the source of truth.
Key takeaways
- Choose per route using freshness, personalization, and failure requirements.
- SSG moves rendering ahead of requests; SSR performs it during requests.
- ISR updates generated output under framework-specific regeneration rules.
- SPA navigation can coexist with server-generated HTML; test both entry paths.
Reach designers & developers at work
Put your product next to the tools people use every day. One sponsor per placement, no tracking pixels.
Become a sponsor