Skip to content
intermediate Phase 14 · Server-Side Rendering and PWA

Adding Server-Side Rendering

Enable Angular SSR and hydrate the server-rendered HTML.

45m
0 problems
Topic Progress 0%

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:

  1. Installs @angular/ssr
  2. Creates src/server.ts (server entry point)
  3. Updates angular.json with a server build target
  4. 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

  1. Server renders HTML with component state
  2. Browser displays the HTML immediately
  3. Client JavaScript loads and "adopts" the existing DOM
  4. Angular attaches event listeners and change detection
  5. 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?

Question 1 options

2. What is hydration?

Question 2 options

3. How do you handle browser-only APIs in SSR?

Question 3 options

Flashcards

Question

What does SSR do?

Answer

Renders first HTML on server. Client hydrates. Faster FCP, better SEO.

Question

What is hydration?

Answer

Client JavaScript adopts server-rendered HTML instead of rebuilding DOM.

Question

How to handle browser-only APIs?

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:

  1. Server renders HTML
  2. Browser displays immediately
  3. Client hydrates
  4. App becomes interactive

Browser-only APIs:

if (isPlatformBrowser(this.platformId)) {
  localStorage.setItem('key', 'value');
}

Continue Learning