Mode follows data availability
Client renders the application in the browser; Server produces HTML per request; Prerender generates documents during build. A hybrid strategy chooses per route rather than imposing one decision on every page. Public articles known beforehand can suit prerendering, while session-specific data needs appropriately timed retrieval and isolation.
The choice influences cost and experience but does not replace measurements in the actual product. Ahead-of-time HTML also does not replace appropriate titles, substantial content, response status and indexing policy.
Enumerate routes during build
getPrerenderParams supplies parameter maps identifying documents to generate for a parameterized route. In the example, two slugs produce two known articles/:slug instances. Enumeration must use build-available information rather than a future visitor’s identity.
More parameters can increase build time and file volume. Also define behavior for addresses not enumerated according to complete application configuration. The example bounds the known list without implementing a complete policy for every possible slug.
Code compatible with server and browser
Constructing a component on the server does not automatically provide window, navigator or browser layout APIs. Work depending on those APIs needs a platform-appropriate implementation or initialization at a browser-only point such as afterNextRender.
Keep initial output consistent: choosing structurally different templates through a platform condition can create hydration mismatch. The solution is not merely suppressing an undefined-variable error. Identify data required by initial HTML and work that can occur later when the environment supports interaction.
Hydration requires structural correspondence
Hydration restores the client application by reusing server-produced DOM. provideClientHydration must participate in the appropriate client and server bootstrap providers. Correspondence includes structure, comments and relevant whitespace rather than visible text alone.
An optimizer removing nodes or a library moving them before hydration can alter the contract. Invalid HTML can also be repaired by the browser into an unexpected tree. When diagnosing, compare server output, the response after intermediaries and the tree found on the client.
Interactions, stability and scoped workarounds
Event replay retains supported native interactions occurring before the application can handle them and replays them after hydration. It is neither a durable queue nor a guarantee of exactly one remote commit. Application stability also conditions hydration phases; investigate pending work when delays occur rather than accepting arbitrary waits. ngSkipHydration can isolate an incompatible component, but is valid only on a component host and recreates its subtree.
Hydration benefits are lost in that scope; the structural cause still needs correction.
Per-request state and transferred data
A mutable object configured as a top-level useValue provider can persist across requests in the server process. If it contains user data, that scope is wrong for request isolation. An appropriate factory creates values at the intended time and scope.
HTTP transfer cache also needs analysis: data can be serialized into initial HTML and reused by the browser until stability. Documented exclusions for credentials and cache-forbidding rules should not be removed indiscriminately. Confirm recipients and permitted reuse before changing that configuration.
Acceptance based on observed behavior
To accept a release, relate configuration to outcomes: initial documents contain expected content, routes represent correct identity, hydration preserves interaction and private data stays within authorized scope. Also exercise relevant failures in an appropriate environment and distinguish observation from inference.
This path teaches contract interpretation through choices and scenarios; it requires no excerpt execution for assessment. Plausible configuration or an isolated test does not automatically demonstrate performance, actual indexing, full accessibility or whole-system security.
// Reading example: server route configuration fragment, not a complete application.
import {ApplicationConfig} from '@angular/core';
import {RenderMode, ServerRoute, provideServerRendering, withRoutes} from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
{
path: 'articles/:slug', renderMode: RenderMode.Prerender,
async getPrerenderParams() {
return [{slug: 'routing-contracts'}, {slug: 'state-ownership'}];
},
},
{path: 'account', renderMode: RenderMode.Client},
{path: '**', renderMode: RenderMode.Server},
];
export const serverConfig: ApplicationConfig = {
providers: [provideServerRendering(withRoutes(serverRoutes))],
};
// Browser/server application routes, components, hydration setup and authenticated
// account API are configured separately; this fragment supplies none of those.Two known public articles are enumerated for prerender. account renders on the client and still needs an authenticated API with its own authorization. Remaining routes use SSR. Configuration does not implement components, guarantee confidentiality by selecting Client or demonstrate hydration installation or validation.
Common pitfalls
Prerendering personalized information without isolation; window access during SSR; intermediary node changes; user state in global useValue; indiscriminate transfer caching; ngSkipHydration on arbitrary elements; inferring exactly one remote effect from event replay.
Related topics: Routing, state and navigation decisions · Security boundaries and trusted content · Testing behavior and integration limits
Choose where and when to render, preserve the structure to be hydrated and bound per-user data lifetime. Acceptance should observe content, interaction, isolation and failures within the relevant environment; configuration and test counts are only part of that evidence.
Reference: Route-specific rendering · Angular 22; standalone components