Server-Side Rendering in Modern Angular Applications
Building High-Performance Web Applications
Topics to Be Discussed
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.
import { bootstrapApplication } from '@angular/platform-browser';
import { provideClientHydration } from '@angular/platform-browser';
bootstrapApplication(AppComponent, {
providers: [provideClientHydration()]
});
E-commerce sites, blogs, marketing pages, content-heavy applications, and any app where SEO and initial load performance are critical.
import { provideServerRendering } from '@angular/ssr';
bootstrapApplication(AppComponent, {
providers: [
provideServerRendering(),
provideClientHydration()
]
});
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 |
Modern applications benefit from hybrid rendering - using different modes for different routes based on content requirements
Modern Server-Side Rendering
import { bootstrapApplication } from '@angular/platform-browser';
import { provideServerRendering } from '@angular/ssr';
bootstrapApplication(AppComponent, {
providers: [provideServerRendering()]
});
Angular SSR replaces Angular Universal with simplified setup, better performance, and modern tooling. The @angular/ssr package provides everything needed for server-side rendering.
Modern Application Builder
ng new your-app --ssr
ng add @angular/ssr
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!
Granular Control Over Hydration
Load smaller initial bundles by hydrating only necessary components, then incrementally hydrate others as needed.
providers: [
provideClientHydration(withIncrementalHydration())
]
@defer (hydrate on viewport) {
<heavy-component />
} @placeholder {
<div>Loading...</div>
}
Hydrate when browser is idle
Hydrate when element enters viewport
Hydrate on user interaction
Keep content static (no hydration)
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.
providers: [
provideClientHydration(withEventReplay())
]
providers: [
provideClientHydration(withIncrementalHydration())
]
Build-Time Prerendering
getPrerenderParams
to define dynamic routes
/**
)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
}
}
];
SSG provides the fastest possible load times since files are pre-built and can be cached by CDNs worldwide.
Mix and Match Approaches
Angular v19 introduces Hybrid Rendering - fine-grained control over how different parts of your app are rendered.
export const serverRoutes: ServerRoute[] = [
{ path: "home", renderMode: RenderMode.Prerender }, // Static
{ path: "products", renderMode: RenderMode.Server }, // Dynamic
{ path: "dashboard", renderMode: RenderMode.Client }, // User-specific
];
Choose rendering mode per route based on content requirements
Static pages load instantly, dynamic content renders on-demand
Set status codes and headers per route
Combine SSR, SSG, and CSR in one application
Platform Detection & Safe API Usage
Browser APIs like window
, document
,
localStorage
don't exist on the server.
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);
}
}
}
import { afterNextRender, afterRender } from '@angular/core';
@Component({...})
export class MyComponent {
constructor() {
afterNextRender(() => {
console.log('DOM ready:', document.readyState);
});
afterRender(() => {
});
}
}
Meta Tags & Search Engine Performance
@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 });
}
}
Core Web Vitals & Metrics
Faster content rendering with pre-generated HTML
Reduced delay with Event Replay and hydration
No layout shifts with proper hydration
Faster interactivity with incremental hydration
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
bootstrapApplication(AppComponent, {
providers: [
provideClientHydration(withEventReplay(), withIncrementalHydration())
]
});
Avoiding Hydration Errors
<problematic-component ngSkipHydration />
@Component({
host: { ngSkipHydration: 'true' }
})
export class ProblematicComponent {}
Thank you for your attention!