In Angular, what does provideClientHydration() change about how a server-rendered page starts in the browser, and where must it be provided?
answer
- destroy and re-render vs reuse
- non-destructive
- server and client both
- ngh annotations in transfer state
basics
~10 sprovideClientHydration() makes Angular reuse the server-rendered DOM instead of discarding it and rendering again. It must be in the server bootstrap as well as the client, or no hydration data is sent.
solid answer
~40 sWithout hydration, an Angular app that was rendered on the server throws the server HTML away when it bootstraps and renders every component again, which can flicker and shift layout. `provideClientHydration()` from `@angular/platform-browser` enables non-destructive hydration: the server annotates its output (`ngh` attributes, serialized view data in transfer state, an integrity comment) and the client walks the existing DOM and reuses those nodes. The provider must be part of the server bootstrap too; with the default layout the server config is merged from the browser config, so one call covers both. If the client has it and the server does not, development mode logs NG0505 and the app renders from scratch. In v22 the same call also enables the HTTP transfer cache and incremental hydration by default.
code
ts · 15 linesimport { ApplicationConfig, mergeApplicationConfig } from '@angular/core';
import { provideClientHydration } from '@angular/platform-browser';
import { provideServerRendering, withRoutes } from '@angular/ssr';
import { serverRoutes } from './app.routes.server';
export const appConfig: ApplicationConfig = {
providers: [provideClientHydration()],
};
const serverConfig: ApplicationConfig = {
providers: [provideServerRendering(withRoutes(serverRoutes))],
};
// The server config inherits provideClientHydration() from appConfig.
export const config = mergeApplicationConfig(appConfig, serverConfig);go deeper
Recall that provideClientHydration() comes from @angular/platform-browser and makes Angular reuse server HTML instead of rendering it again.
Explain the annotations the server adds, why the provider must be in the server bootstrap too, and what NG0505 tells you.
Know which defaults the call brings in v22, how to verify hydration in development, and how a missing server provider degrades silently to a full re-render.
Weigh hydration's constraint that server and client DOM must match against its benefits, and decide how teams enforce hydration-safe components across a large codebase.
## Two ways a server-rendered page can start When an Angular page is rendered on the server, the browser first receives finished HTML. Then the JavaScript bundle loads and Angular bootstraps. What happens to the HTML that is already on screen depends on one provider: | Setup | What Angular does with the server HTML | Visible effect | | --- | --- | --- | | No `provideClientHydration()` | Discards it and renders every component from scratch | Possible flicker and layout shift | | `provideClientHydration()` in both configs | Walks the existing DOM and **reuses** the nodes, attaching listeners and bindings | No re-creation of DOM nodes | Angular calls the second path **non-destructive hydration**. It has been a stable public API since v17 (`provideClientHydration` is exported from `@angular/platform-browser`). ## Enabling it ```ts import { ApplicationConfig } from '@angular/core'; import { provideClientHydration } from '@angular/platform-browser'; export const appConfig: ApplicationConfig = { providers: [provideClientHydration()], }; ``` - `ng add @angular/ssr` adds this call to the root providers for you. - The **server** must include it too. With the default layout the server config is merged from the browser config (`mergeApplicationConfig`), so one call covers both. In a custom setup where the two configs share nothing, it must be added to the server side explicitly. - In an NgModule app, the call goes in the root module's `providers`. ## What the server adds when hydration is on When the server render has hydration enabled, it annotates its output so the client can match it: 1. component host elements receive an `ngh` attribute pointing at serialized view data; 2. that data travels to the browser inside the transfer state (under a `__nghData__` key); 3. a `<!--nghm-->` comment marks that the HTML has not been altered since rendering; 4. comment and text markers remain where Angular needs them to locate nodes. On the client, Angular checks for that serialized data. If it is present, hydration runs; if it is absent, hydration stays off and the app renders from scratch. ## What goes wrong when the two sides disagree - **Client has it, server does not.** In development Angular logs warning **NG0505** ("no hydration info in server response") and renders destructively. Routes served with `RenderMode.Client` are marked so this warning is suppressed, because there is nothing to hydrate. - **DOM changed between server and client.** Direct DOM manipulation, invalid HTML nesting or stripped comments produce the NG0500-family errors covered separately. ## What else the call switches on `provideClientHydration()` is not a single feature. In Angular 22.2 it also enables, by default: - the **HTTP transfer cache**, so `HttpClient` responses fetched on the server are reused instead of fetched again; - **incremental hydration**, which also turns on event replay; - in development, stability debugging that reports when the app takes too long to become stable. Each of those has its own opt-out feature function (`withNoHttpTransferCache()`, `withNoIncrementalHydration()`) and its own configuration story. For the full-app hydration question, the point is that one provider, present on both sides, is what turns "render twice" into "render once and reuse". ## How to confirm it works - In development the browser console prints hydration statistics: how many components and nodes were hydrated. - Angular DevTools can overlay which parts of the page were hydrated and highlight the component that caused a mismatch. ## A note on NgModule apps In an NgModule application the call goes in the root module's `providers`. Because the server module imports that root module in the default layout, the server side receives it automatically; a hand-built server module that does not import it needs its own call. ## Quick recap for an interview - Without the provider, server HTML is thrown away and rebuilt. - With it, the DOM is reused, which requires server and client to produce the same structure. - It must be present in the server bootstrap as well as the client, and it brings several related defaults with it in v22.
- What happens if only the browser config includes provideClientHydration()?The server sends no hydration data, so the client keeps hydration off and renders from scratch. In development Angular logs NG0505 to say hydration was requested but the response had no serialized information. Adding the provider to the server bootstrap fixes it.
- Is it harmful to keep provideClientHydration() for routes rendered only in the browser?No. A `RenderMode.Client` response carries no hydration data, so the client simply renders normally, and those pages are marked so the NG0505 warning is not logged.
- How can you confirm hydration actually ran?In development the console prints hydration statistics with the number of components and nodes hydrated. Angular DevTools can overlay hydrated regions and highlight the component where a mismatch occurred.
Moving into a furnished flat: without hydration you empty every room and refurnish it; with hydration you keep the furniture and just plug in the appliances.
saying these in an interview costs you the question
- Hydration is on by default in every server-rendered Angular app
- provideClientHydration() is only needed in the browser config
- Hydration makes the server HTML interactive before the bundle loads
- Hydration re-renders the page on the client and then diffs it
- provideClientHydration() only affects DOM reuse and nothing else in v22