Skip to the solution
HardFrontend10 min read

How does Hydration work in modern Angular SSR, and what is non-destructive hydration?

178 views

The problem

Question presented to candidate: "We render our Angular app on the server, but users see the page flash and their first clicks do nothing. Explain what hydration is, what Angular means by non-destructive hydration, and what we should turn on."

What a strong answer should cover:

  • Hydration: making server-rendered HTML interactive in the browser by attaching Angular to the existing DOM.
  • Destructive vs non-destructive: old behaviour wiped the server DOM and re-rendered (flicker, wasted work); non-destructive hydration (v16 preview, stable v17) reuses the nodes.
  • How to enable it: provideClientHydration() in the app config; the server adds ngh annotations and an ng-state script that the browser reads.
  • Event replay: user events captured before hydration are replayed afterwards.
  • Incremental hydration: @defer (hydrate on ...) keeps parts of the page dehydrated until needed; on by default in v22.
  • How to confirm it works: the dev-mode hydration log and the absence of flicker.

Clarifying questions expected:

  • "Are we on a version with provideClientHydration, or still on the older Universal setup?"
  • "Do the first clicks fail everywhere, or only on heavy pages that take long to boot?"

Code / implementation expected: Optional β€” the provider line, and one @defer block with a hydrate trigger.

  • ssr
  • hydration
  • performance

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

10 min read Β· 10 sections

Read the code

AngularTurning hydration on: one provider in the app config
import { ApplicationConfig, Component, signal } from "@angular/core";
import { provideClientHydration } from "@angular/platform-browser";

@Component({
  selector: "app-root",
  template: `
    <h1>Basket</h1>
    <ul>
      @for (item of items(); track item) { <li>{{ item }}</li> }
    </ul>
    <button (click)="items.update(list => [...list, 'Scone'])">Add scone</button>
  `,
})
export class AppComponent {
  items = signal(["Tea", "Coffee"]);
}

// The one line that turns destructive re-rendering into hydration.
// Since v22 this also turns on incremental hydration, and with it event replay.
export const appConfig: ApplicationConfig = {
  providers: [provideClientHydration()],
};
AngularIncremental hydration: a @defer block that stays dehydrated until the user interacts
import { ApplicationConfig, Component, signal } from "@angular/core";
import { provideClientHydration } from "@angular/platform-browser";
@Component({ selector: "app-reviews", template: `<p>{{ n() }} reviews</p><button id="more" (click)="n.set(n() + 1)">more</button>` })
export class ReviewsComponent { n = signal(5); }
@Component({
  selector: "app-root",
  imports: [ReviewsComponent],
  template: `<h1>Product</h1>
    @defer (hydrate on interaction) { <app-reviews /> } @placeholder { <p>reviews placeholder</p> }`,
})
export class AppComponent {}
export const appConfig: ApplicationConfig = { providers: [provideClientHydration()] };

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 118 of 121 in Angular

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Angular questions
Up nextHard

What is the effect() function in Angular Signals, and when should you NOT use it?

Continue