Skip to content
FrontHeaven
Light mode
Level 3 — AdvancedAdvanced 55 min read

Server-Side Rendering (SSR), Hydration & SSG

Master Angular rendering modes: Client-Side Rendering (CSR), Server-Side Rendering (SSR with @angular/ssr), Static Site Generation (SSG), Non-Destructive Hydration, and Event Replay.

Angular progress0%

Server-Side Rendering (SSR), Hydration & SSG

In modern enterprise web development, delivering instant initial page loads, optimal Search Engine Optimization (SEO) scores, and high Core Web Vitals (Largest Contentful Paint) requires hybrid rendering architectures. Modern Angular provides full server-side rendering capabilities via @angular/ssr, supporting Server-Side Rendering (SSR), Static Site Generation (SSG / Prerendering), Non-Destructive Hydration, and Event Replay.

text
┌─────────────────────────────────────────────────────────────┐
│                 Angular SSR & Hydration Lifecycle           │
│                                                             │
│  1. Client Requests URL (/products)                         │
│             │                                               │
│             ▼                                               │
│  2. Node.js Server Renders Angular App via @angular/ssr     │
│     ├── Fetches API data via HttpClient                     │
│     ├── Stores API data in TransferState cache              │
│     └── Emits complete semantic HTML document               │
│             │                                               │
│             ▼                                               │
│  3. Browser Displays Server-Rendered HTML Instantly (Fast LCP)│
│     └── Event Replay captures user clicks before hydration  │
│             │                                               │
│             ▼                                               │
│  4. Client Downloads JavaScript & Non-Destructive Hydration  │
│     ├── Reuses existing DOM nodes (Zero screen flicker)     │
│     ├── Replays captured user events                        │
│     └── App becomes fully interactive SPA                   │
└─────────────────────────────────────────────────────────────┘

1. Enabling Angular SSR and Non-Destructive Hydration

To add SSR and hydration to an Angular application:

Terminal
# Add SSR to an existing project
ng add @angular/ssr

In src/app/app.config.ts:

TypeScript
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
import { provideHttpClient, withFetch } from '@angular/common/http';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideHttpClient(withFetch()),
    // Enable Non-Destructive Hydration and Event Replay
    provideClientHydration(
      withEventReplay() // Replays clicks made before JS finished downloading
    )
  ]
};

2. Preventing Duplicate API Calls with TransferState

Without TransferState, an application rendered on the server executes HTTP requests during SSR, sends HTML to the browser, and then the client-side JavaScript executes the exact same HTTP requests again upon bootstrap.

Angular's HttpClient automatically serializes and transfers cached GET responses from the server to the client when hydration is enabled:

TypeScript
import { Component, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { toSignal } from '@angular/core/rxjs-interop';

@Component({
  selector: 'app-catalog',
  standalone: true,
  template: `
    <ul>
      @for (prod of products(); track prod.id) {
        <li>{{ prod.name }} - \${{ prod.price }}</li>
      }
    </ul>
  `
})
export class CatalogComponent {
  private http = inject(HttpClient);

  // Automatically cached on server and dehydrated to client
  readonly products = toSignal(this.http.get<any[]>('/api/products'));
}

3. Resolving Hydration Mismatch Errors

A hydration mismatch occurs when the HTML generated on the server does not match the initial DOM structure generated by the client JavaScript (e.g. using new Date() or Math.random() directly in templates, or referencing window.innerWidth).

To fix hydration mismatches:

  • Use afterNextRender(() => ...) for browser-specific APIs.
  • Use the ngSkipHydration attribute on third-party DOM components that cannot be safely hydrated.
HTML
<!-- Skip hydration on third-party canvas or legacy jQuery widget -->
<div ngSkipHydration>
  <canvas id="legacy-chart"></canvas>
</div>

Summary & Key Takeaways

  • Angular SSR renders complete HTML on the server for maximum SEO and lightning-fast LCP.
  • Non-destructive hydration attaches event listeners to existing DOM nodes without destroying and recreating them.
  • withEventReplay() captures user interactions during page load and replays them once JavaScript hydrates.
  • TransferState eliminates duplicate network requests between server and client.

Best Practices & Senior Guidance

  1. Always Use withEventReplay(): Enable provideClientHydration(withEventReplay()) to ensure user clicks during initial load are never dropped.
  2. Never Reference window or document Globally: Wrap browser-specific API calls inside afterNextRender() or guard with isPlatformBrowser(platformId).
  3. Use Static Site Generation (SSG) for Marketing Pages: Configure static prerendering in angular.json for content that does not change per user session.

Finished studying? Lock it in.

Mark this lesson as completed to track your journey.