In Angular 22, how is incremental hydration enabled or disabled, and what does it switch on implicitly?
answer
- default since v22
- one opt-out function
- deprecated opt-in function
- brings event replay
basics
~10 sIn Angular 22 provideClientHydration() enables incremental hydration by default; withNoIncrementalHydration() opts out, and withIncrementalHydration() is deprecated. It also enables event replay, so withEventReplay() is redundant.
solid answer
~40 sIncremental hydration keeps server-rendered `@defer` blocks with `hydrate` triggers dehydrated until a trigger fires. From v22 it is part of the default `provideClientHydration()`; before that it had to be requested with `withIncrementalHydration()`, which is now deprecated with removal intended in v24. To opt out you pass `withNoIncrementalHydration()`. It depends on event replay and turns it on, so `withEventReplay()` can be removed; opting out also removes that replay unless you add `withEventReplay()` back. If templates use `hydrate` triggers while incremental hydration is off, Angular logs NG0508 and those blocks do not get incremental hydration. It still needs a server-rendered route and full hydration.
code
ts · 16 linesimport { ApplicationConfig } from '@angular/core';
import {
provideClientHydration,
withEventReplay,
withNoIncrementalHydration,
} from '@angular/platform-browser';
// Default in v22: incremental hydration and event replay are both on.
export const appConfig: ApplicationConfig = {
providers: [provideClientHydration()],
};
// Opting out: re-add event replay explicitly if it is still wanted.
export const optedOutConfig: ApplicationConfig = {
providers: [provideClientHydration(withNoIncrementalHydration(), withEventReplay())],
};go deeper
Recall that in v22 provideClientHydration() already enables incremental hydration and that withNoIncrementalHydration() is the opt-out.
Explain why incremental hydration brings event replay, what NG0508 reports, and why the route must be server-rendered for it to matter.
Plan the v20-v21 to v22 upgrade: remove the deprecated opt-in, know what an opt-out also removes, and confirm which blocks actually change.
Decide whether the organisation adopts the default or opts out, and document the reason so later upgrades do not silently change behaviour.
## What changed in Angular 22 **Incremental hydration** lets server-rendered `@defer` blocks stay **dehydrated** (present as HTML, not yet active) until a `hydrate` trigger fires. It became a stable API in v20 behind an explicit feature, `withIncrementalHydration()`. In **v22** the default flipped: | Angular version | How incremental hydration is enabled | | --- | --- | | v19 (developer preview) and v20-v21 | `provideClientHydration(withIncrementalHydration())` | | v22 and later | On by default with `provideClientHydration()` | | v22 opt-out | `provideClientHydration(withNoIncrementalHydration())` | `withIncrementalHydration()` still exists in v22 but is **deprecated**, with the stated intent to remove it in v24. Passing both `withIncrementalHydration()` and `withNoIncrementalHydration()` in one call is a configuration error in development mode. ## The minimum setup in v22 ```ts import { ApplicationConfig } from '@angular/core'; import { provideClientHydration } from '@angular/platform-browser'; export const appConfig: ApplicationConfig = { providers: [provideClientHydration()], }; ``` Nothing else is required at the provider level. The work moves into templates: a `@defer` block becomes an incremental hydration boundary when you add a trigger that starts with `hydrate`. Prerequisites that still apply: - the route must be **server-rendered** (or prerendered), because there is nothing to hydrate in a page the browser rendered itself; - full-app hydration must be on, which `provideClientHydration()` provides; - the same constraints as full hydration hold: no direct DOM manipulation that changes server HTML, and valid HTML structure. ## What it switches on implicitly Incremental hydration **depends on and enables event replay**. The provider that turns incremental hydration on also installs the event replay machinery, so: 1. clicks and other listened-to events that happen on a dehydrated block, or before hydration finishes, are queued; 2. once the relevant block (and its parent blocks) hydrate, the queued events are replayed to the real listeners. The guide's advice follows directly: if an app already lists `withEventReplay()`, it can be removed, because the default configuration already includes it. The reverse is the trap: an app that opts out with `withNoIncrementalHydration()` also loses the event replay that came with it, unless it adds `withEventReplay()` back. ## When the configuration and templates disagree If templates use `hydrate` triggers but incremental hydration is not enabled, for example because the app opted out or never provided hydration, Angular logs warning **NG0508** once. The message states that some `@defer` blocks use `hydrate` triggers and that incremental hydration was not enabled, so those blocks do not get incremental hydration. ## Upgrade checklist from v20-v21 - Remove `withIncrementalHydration()` from `provideClientHydration(...)`; it is redundant and deprecated. - Remove `withEventReplay()` if you want the config minimal; it is harmless to keep. - If the app previously used hydration **without** incremental hydration, the upgrade turns it on. Existing `@defer` blocks without `hydrate` triggers are unaffected, so behaviour changes only where templates opt in. - If a team decides against it, record why next to `withNoIncrementalHydration()` and re-add `withEventReplay()` if replay is still wanted. ## How to verify it in a running app 1. Serve a page with a `hydrate` trigger and open the network panel: the block's chunk should not load until the trigger fires. 2. Check the console in development mode for NG0508; its absence means the configuration and templates agree. 3. Click inside a dehydrated block before its code arrives and confirm the handler still runs once it has, which shows event replay is active. ## Recap - One provider call, `provideClientHydration()`, enables incremental hydration in v22. - It brings event replay with it. - `withNoIncrementalHydration()` is the only switch you normally write, and only to opt out.
- What does Angular do if a template uses hydrate triggers but incremental hydration is off?It logs warning NG0508 once, saying some `@defer` blocks use `hydrate` triggers but incremental hydration was not enabled. Those blocks do not get incremental hydration, so check that `provideClientHydration()` is present and that `withNoIncrementalHydration()` was not passed.
- Does upgrading to v22 change blocks that have no hydrate triggers?No. Only `@defer` blocks with `hydrate` triggers become incremental hydration boundaries. Other deferred blocks keep their previous behaviour, so the upgrade changes templates only where they already opted in.
saying these in an interview costs you the question
- In Angular 22 you must add withIncrementalHydration() to use hydrate triggers
- Incremental hydration works on client-rendered routes without server rendering
- withNoIncrementalHydration() leaves event replay switched on
- Upgrading to v22 changes every @defer block in the app
- withEventReplay() must be listed next to incremental hydration