Back to Blog

How Angular Detects That SSR Rendering Is Complete

How Angular Detects That SSR Rendering Is Complete

When Angular does Server-Side Rendering, the server must answer one core question:

"Is the page fully ready to send to the browser?"

Because during rendering:

  • components load,
  • APIs are called,
  • asynchronous operations run,
  • Observables emit values.

If Angular sends HTML too early, the page can be incomplete.
So Angular waits until everything render-critical is finished.

The key mechanism: Zone.js

Angular uses Zone.js to track asynchronous work, including:

  • Promises,
  • timers such as setTimeout,
  • HTTP requests,
  • async/await,
  • async flows tied to app boot/render.

When tracked tasks settle, Angular can determine that the app is stable.

This is the concept of application stability.

The important signal: ApplicationRef.isStable

Angular internally exposes stability via:

ApplicationRef.isStable

It emits true when the app reaches a stable state:

  • microtasks are drained,
  • no pending render-critical async work remains in Angular's zone.

During SSR, Angular waits for this stable signal before producing final HTML.

SSR rendering flow (internal)

  1. Request reaches server
    User requests a route like GET /products.
  2. Angular bootstraps app on server
    Server runtime starts the route render.
  3. Components start loading
    Example: ProductComponent initializes and requests data.
  4. Zone.js tracks async operations
    Pending task count is non-zero while work is in progress.
  5. API returns data
    Component state updates and DOM output updates.
  6. Async tasks complete
    Zone reports no remaining pending render-critical tasks.
  7. App becomes stable
    ApplicationRef.isStable emits true.
  8. Angular serializes DOM
    Server renderer converts DOM to an HTML string.
  9. HTML is sent to browser
    Browser receives complete first content.

Why this is important

Without stability checks, SSR might send placeholder HTML like:

Loading products...

instead of actual content:

Product A, Product B, Product C

That defeats the purpose of SSR.

Real example

ngOnInit() {
  this.http.get('/api/products').subscribe((data) => {
    this.products = data;
  });
}

During SSR, Angular waits for this request to resolve before final HTML is serialized.

Advanced caveat

Some async tasks may never naturally finish, such as:

  • setInterval,
  • WebSocket connections,
  • long polling loops.

Angular cannot wait forever, so SSR pipelines include timeout and stability safeguards to avoid hanging responses.