Skip to content

Angular Server-Side Rendering

Server-side rendering (SSR) renders an Angular application's initial HTML on the server before sending it to the browser. This lesson explains why that matters and how to enable it.

What Is Server-Side Rendering?

By default, a single-page Angular app sends the browser a nearly empty HTML shell, and JavaScript builds the actual UI client-side after it downloads and executes. SSR instead renders the initial view to full HTML on the server (or at build time), so the browser receives meaningful content immediately.

This improves perceived load time (users see content sooner), and search engine crawlers, some of which don't execute JavaScript reliably, see fully rendered content rather than an empty shell.

// enabling SSR in an existing project
ng add @angular/ssr

// resulting scripts (added to package.json)
"build": "ng build",
"serve:ssr:my-app": "node dist/my-app/server/server.mjs"

ng add @angular/ssr wires up a Node.js server entry point and the necessary build configuration automatically.

How SSR Changes the Request Lifecycle

Browser requests a page
        |
        v
Node.js server renders the Angular app to HTML for that URL
        |
        v
Browser receives full HTML immediately, then hydrates it with Angular's JS
        |
        v
App becomes fully interactive (hydration complete)
  • The server runs the same Angular application code to produce HTML for the requested URL.
  • The browser displays that HTML immediately, before any Angular JavaScript has run.
  • "Hydration" is the process of Angular's client-side code attaching to that existing HTML and making it interactive, without re-rendering it from scratch.
  • Non-browser APIs (like window or document) aren't available during server rendering and must be guarded against.

Server-Side Rendering Cheatsheet

Key commands and concepts for Angular SSR.

Task Command/Concept
Add SSR to an existing project ng add @angular/ssr
Enable SSR when creating a project ng new my-app (prompted) or ng new my-app --ssr
Run the SSR-enabled server locally npm run serve:ssr:my-app
Hydration Angular reuses server-rendered DOM instead of re-rendering it
Guarding browser-only APIs isPlatformBrowser(inject(PLATFORM_ID))
Static prerendering Generating fully static HTML at build time for specific routes

Why SSR Improves SEO and Perceived Load Time

Search engines generally reward pages that deliver meaningful content quickly and reliably. SSR removes the dependency on client-side JavaScript execution for that initial content, both improving how crawlers see the page and how quickly real users perceive the page as "loaded".

Hydration: Reusing Server-Rendered DOM

Without hydration, a client-side Angular app would simply re-render everything from scratch after loading, throwing away the server-rendered DOM and causing a visible flicker. Angular's hydration feature instead reuses the existing DOM nodes and attaches event listeners and reactivity to them directly.

Guarding Browser-Only Code

Code that references window, document, or localStorage directly will throw on the server, where those globals don't exist. Guard such code with a platform check, or better, isolate it behind an abstraction only invoked in browser contexts.

import { PLATFORM_ID, inject } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';

export class ThemeService {
  private platformId = inject(PLATFORM_ID);

  getSavedTheme() {
    if (!isPlatformBrowser(this.platformId)) return 'light';
    return localStorage.getItem('theme') ?? 'light';
  }
}

Common Mistakes

  • Directly accessing window/document/localStorage in code paths that also run during server rendering, causing runtime errors.
  • Not testing the actual SSR build (npm run serve:ssr:...), assuming the dev server (ng serve) behaves identically.
  • Fetching the same data twice, once on the server and again unnecessarily on the client after hydration.
  • Expecting SSR alone to fix all performance problems; it addresses initial load and SEO specifically, not runtime interaction performance.

Key Takeaways

  • SSR renders the initial HTML on the server, improving perceived load time and SEO.
  • Hydration reuses server-rendered DOM instead of discarding and re-rendering it client-side.
  • Browser-only APIs need explicit guarding since they aren't available during server rendering.
  • ng add @angular/ssr sets up SSR infrastructure automatically for an existing project.

Pro Tip

After enabling SSR, always test with the actual SSR server (npm run serve:ssr:my-app) rather than only ng serve, several classes of bugs (browser-API access, hydration mismatches) only appear when code genuinely executes on the server.