1/16

Angular SSR

Server-Side Rendering in Modern Angular Applications

Building High-Performance Web Applications

2/16

Agenda

Topics to Be Discussed

Presentation Overview

  • Introduction to Server-Side Rendering (SSR)
  • Benefits and Considerations of SSR in Angular
  • Rendering Modes: CSR, SSR, and SSG
  • Angular SSR Architecture and Setup
  • Step-by-Step Setup
  • Incremental Hydration (v19+)
  • Event Replay for User Interactions
  • Static Site Generation (SSG)
  • Hybrid Rendering in Angular v19+
  • Handling Browser-Specific Code
  • SEO Optimization Strategies
  • Performance Benefits and Core Web Vitals
  • Common Pitfalls and Debugging Techniques
3/16

What is SSR?

Server-Side Rendering (SSR) is a web development technique where the server generates HTML content of a web page, providing faster initial load times and improved user experience.

How it Works

  • Server executes Angular application and generates HTML
  • Full HTML page sent to browser immediately
  • JavaScript takes over for interactivity (hydration)
  • Results in faster perceived load times
12345
import { bootstrapApplication } from '@angular/platform-browser';
import { provideClientHydration } from '@angular/platform-browser';

bootstrapApplication(AppComponent, {
  providers: [provideClientHydration()]
});
4/16

Why use SSR in Angular?

✅ Benefits

  • Improved Core Web Vitals (LCP, FID, CLS)
  • Better SEO and social media sharing
  • Faster perceived load times
  • Better performance on slow networks
  • Reduced time to interactive

⚠️ Considerations

  • Increased server complexity
  • Higher server hosting costs
  • Browser API limitations
  • Third-party library constraints
  • Development complexity

🎯 Perfect for

E-commerce sites, blogs, marketing pages, content-heavy applications, and any app where SEO and initial load performance are critical.

123456
import { provideServerRendering } from '@angular/ssr';

bootstrapApplication(AppComponent, {
  providers: [
    provideServerRendering(),
    provideClientHydration()
  ]
});
5/16

Rendering Modes

CSR vs SSR vs SSG (Prerendering)

Rendering Mode When HTML is Generated Best For Performance
CSR (Client-Side) In the browser at runtime SPAs, dashboards, user-specific content Slower initial load
SSR (Server-Side) On server per request Dynamic content, personalized pages Fast initial load
SSG (Static Generation) At build time Static content, blogs, marketing pages Fastest load times

💡 Key Insight

Modern applications benefit from hybrid rendering - using different modes for different routes based on content requirements

6/16

Angular SSR Overview

Modern Server-Side Rendering

🏗️ Architecture

  • Built on Angular Universal foundation
  • Uses Node.js Express server
  • Supports multiple deployment options
  • Integrated with Angular CLI

📦 Core Components

  • @angular/ssr package
  • Application Builder
  • Server configuration
  • Hydration providers
123456
import { bootstrapApplication } from '@angular/platform-browser';
import { provideServerRendering } from '@angular/ssr';

bootstrapApplication(AppComponent, {
  providers: [provideServerRendering()]
});

🎯 Evolution from Angular Universal

Angular SSR replaces Angular Universal with simplified setup, better performance, and modern tooling. The @angular/ssr package provides everything needed for server-side rendering.

7/16

Step-by-Step Setup

Modern Application Builder

  1. New Project:
    1
    ng new your-app --ssr
    
  2. Existing Project:
    1
    ng add @angular/ssr
    
  3. Build & Serve:
    12
    ng build        # Builds both browser & server
    ng serve:ssr    # Development with SSR
    

💡 Pro Tip: The new Application Builder automatically handles SSR and SSG in one build command!

8/16

Incremental Hydration (v19+)

Granular Control Over Hydration

🎯 Purpose

Load smaller initial bundles by hydrating only necessary components, then incrementally hydrate others as needed.

12345678
providers: [
  provideClientHydration(withIncrementalHydration())
]

@defer (hydrate on viewport) {
  <heavy-component />
} @placeholder {
  <div>Loading...</div>
}
hydrate on idle

Hydrate when browser is idle

hydrate on viewport

Hydrate when element enters viewport

hydrate on interaction

Hydrate on user interaction

hydrate never

Keep content static (no hydration)

9/16

Event Replay

Capturing User Interactions During Hydration

Event Replay captures user interactions that occur before hydration completes and replays them afterward, ensuring no user actions are lost.

📋 Three Phases

  • Capture: Store user interactions
  • Queue: Keep events in memory
  • Replay: Execute after hydration

🎯 Supported Events

  • Click events
  • Keyboard interactions
  • Mouse events (hover, mouseover)
  • Focus events
123456
providers: [
  provideClientHydration(withEventReplay())
]

providers: [
  provideClientHydration(withIncrementalHydration())
]
10/16

Static Site Generation (SSG)

Build-Time Prerendering

⚡ How SSG Works

  • HTML generated at build time
  • Static files served to users
  • No server processing required
  • Can be deployed to CDN

🎯 Best Use Cases

  • Marketing websites
  • Documentation sites
  • Blogs and articles
  • Product catalogs

🔧 Parameterized Routes

  • Use getPrerenderParams to define dynamic routes
  • Generate multiple static pages for parameterized routes
  • Supports catch-all routes (e.g., /**)
  • Runs at build time, avoids browser/server APIs
123456789101112
import { RenderMode, ServerRoute } from '@angular/ssr';
import { inject } from '@angular/core';

export const serverRoutes: ServerRoute[] = [
  {
    path: 'post/:id',
    renderMode: RenderMode.Prerender,
    async getPrerenderParams() {
      const dataService = inject(PostService);
      const ids = await dataService.getIds(); // ['1', '2', '3']
      return ids.map(id => ({ id })); // /post/1, /post/2, /post/3
    }
  }
];

🔧 Server Configuration

  • Configure fallback strategies (Server, Client, None)
  • Set custom headers and status codes
  • Handle redirects at server level

🚀 Performance Advantage

SSG provides the fastest possible load times since files are pre-built and can be cached by CDNs worldwide.

11/16

Hybrid Rendering (v19+)

Mix and Match Approaches

Angular v19 introduces Hybrid Rendering - fine-grained control over how different parts of your app are rendered.

12345
export const serverRoutes: ServerRoute[] = [
  { path: "home", renderMode: RenderMode.Prerender },     // Static
  { path: "products", renderMode: RenderMode.Server },    // Dynamic
  { path: "dashboard", renderMode: RenderMode.Client },   // User-specific
];
🎯 Route-Level Control

Choose rendering mode per route based on content requirements

⚡ Optimal Performance

Static pages load instantly, dynamic content renders on-demand

🛠️ Custom Headers

Set status codes and headers per route

📦 Best of All Worlds

Combine SSR, SSG, and CSR in one application

12/16

Handling Browser-Specific Code

Platform Detection & Safe API Usage

⚠️ The Challenge

Browser APIs like window, document, localStorage don't exist on the server.

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

@Component({...})
export class MyComponent {
  private platform = inject(PLATFORM_ID);
  
  ngOnInit() {
    if (isPlatformBrowser(this.platform)) {
      console.log(window.location.href);
    }
  }
}
12345678910
import { afterNextRender, afterRender } from '@angular/core';

@Component({...})
export class MyComponent {
  constructor() {
    afterNextRender(() => {
      console.log('DOM ready:', document.readyState);
    });
    
    afterRender(() => {
    });
  }
}
13/16

SEO Optimization

Meta Tags & Search Engine Performance

🏷️ Essential Meta Tags

  • Title (60-70 characters)
  • Description (120-150 characters)
  • Open Graph tags
  • Twitter Card tags

🎯 SSR Advantages

  • Search crawlers get full HTML
  • Social media previews work
  • No JavaScript execution required
  • Better indexing performance
123456789
@Injectable()
export class SeoService {
  private title = inject(Title);
  private meta = inject(Meta);

  updatePageSEO(data: SEOData) {
    this.title.setTitle(data.title);
    this.meta.updateTag({ name: 'description', content: data.description });
    this.meta.updateTag({ property: 'og:title', content: data.title });
    this.meta.updateTag({ property: 'og:description', content: data.description });
  }
}
14/16

Performance Benefits

Core Web Vitals & Metrics

📊 LCP (Largest Contentful Paint)

Faster content rendering with pre-generated HTML

⚡ FID (First Input Delay)

Reduced delay with Event Replay and hydration

📐 CLS (Cumulative Layout Shift)

No layout shifts with proper hydration

🕒 TTI (Time to Interactive)

Faster interactivity with incremental hydration

📈 Measurable Improvements

  • Load Time: 40-60% faster initial page loads
  • Bundle Size: Smaller initial JavaScript with incremental hydration
  • SEO Score: Perfect Lighthouse SEO scores
  • User Experience: Immediate content visibility
1234567
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';

bootstrapApplication(AppComponent, {
  providers: [
    provideClientHydration(withEventReplay(), withIncrementalHydration())
  ]
});
15/16

Common Pitfalls & Debugging

Avoiding Hydration Errors

🚫 Common Issues

  • Direct DOM manipulation
  • Invalid HTML structure
  • Browser API usage on server
  • Inconsistent server/client rendering
  • Third-party script interference

🛠️ Debugging Tools

  • Angular DevTools hydration overlay
  • Console hydration statistics
  • Browser Network tab analysis
  • HTML validation tools
  • Lighthouse performance audits
123456
<problematic-component ngSkipHydration />

@Component({
  host: { ngSkipHydration: 'true' }
})
export class ProblematicComponent {}
16/16

Questions & Answers

Thank you for your attention!