Enabling SSR
Angular SSR renders the first HTML response on the server, so content paints before JavaScript runs. The client then hydrates the server-rendered HTML.
Adding SSR to an Existing Project
ng add @angular/ssr
This command:
- Installs @angular/ssr
- Creates src/server.ts (server entry point)
- Updates angular.json with a server build target
- Updates package.json with serve:ssr script
Generated Server Entry Point
// src/server.ts
import { CommonEngine } from '@angular/ssr/node';
export function run(): void {
const server = express();
const distFolder = join(process.cwd(), 'dist/my-app/browser');
const indexHtml = join(distFolder, 'index.html');
const commonEngine = new CommonEngine();
server.get('*.*', express.static(distFolder, { maxAge: '1y' }));
server.get('*', (req, res, next) => {
const { protocol, originalUrl, baseUrl, headers } = req;
commonEngine
.render({
bootstrap: AppServerModule,
documentFilePath: indexHtml,
url: `${protocol}://${headers.host}${originalUrl}`,
publicPath: distFolder,
providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
})
.then(html => res.send(html))
.catch(err => next(err));
});
}
SSR Flow
1. Browser requests /products
2. Server renders the Angular app to HTML
3. Server sends complete HTML to browser
4. Browser displays content immediately (no blank page)
5. Client JavaScript downloads and hydrates the HTML
6. App becomes interactive
Client Hydration
Hydration adopts server-rendered HTML instead of rebuilding the DOM from scratch, preserving the initial render.
How Hydration Works
- Server renders HTML with component state
- Browser displays the HTML immediately
- Client JavaScript loads and "adopts" the existing DOM
- Angular attaches event listeners and change detection
- App becomes fully interactive
Hydration Benefits
- Faster FCP — Content paints before JavaScript loads
- Better LCP — Largest content is already in the HTML
- SEO — Crawlers see complete HTML without executing JavaScript
- No flicker — No blank page or loading spinner
Handling Browser-Only APIs
// BAD: Direct browser API access breaks SSR
@Component({...})
export class MyComponent {
ngOnInit(): void {
localStorage.setItem('key', 'value'); // Error on server!
}
}
// GOOD: Guard browser-only APIs
import { isPlatformBrowser } from '@angular/common';
import { PLATFORM_ID, inject } from '@angular/core';
@Component({...})
export class MyComponent {
private platformId = inject(PLATFORM_ID);
ngOnInit(): void {
if (isPlatformBrowser(this.platformId)) {
localStorage.setItem('key', 'value');
}
}
}
Running the SSR Server
# Build and serve with SSR
npm run build
npm run serve:ssr
# Or in one command
ng build && ng run my-app:serve-ssr
Quiz
1. What does Angular SSR do?
2. What is hydration?
3. How do you handle browser-only APIs in SSR?
Flashcards
Question
What does SSR do?
Click to reveal answer
Answer
Renders first HTML on server. Client hydrates. Faster FCP, better SEO.
Question
What is hydration?
Click to reveal answer
Answer
Client JavaScript adopts server-rendered HTML instead of rebuilding DOM.
Question
How to handle browser-only APIs?
Click to reveal answer
Answer
isPlatformBrowser(this.platformId) guard.
Revision Notes
Key Takeaways
- 1. ng add @angular/ssr enables SSR
- 2. Server renders first HTML, client hydrates
- 3. isPlatformBrowser guards browser-only APIs
- 4. SSR improves FCP, LCP, and SEO
Interview Tips
- • Explain the SSR flow and hydration
- • Be ready to describe browser-only API handling
- • Mention SEO and performance benefits
Cheat Sheet
SSR Cheat Sheet
Add SSR:
ng add @angular/ssr
Flow:
- Server renders HTML
- Browser displays immediately
- Client hydrates
- App becomes interactive
Browser-only APIs:
if (isPlatformBrowser(this.platformId)) {
localStorage.setItem('key', 'value');
}