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.
You now understand server-side rendering fundamentals. Next, learn about Angular Universal, the broader SSR platform and its related tooling.