This episode covers server-side rendering and Angular Universal: the Universal basics, the difference between prerendering and SSR, SEO and initial load improvements, and hydration and the interaction between server and client.

A standard Angular application is rendered in the browser, so crawlers and users see a blank screen while JavaScript loads. Server-side rendering moves the HTML rendering work to the server, producing a page that's immediately readable.
Episode 21 covers the Angular Universal basics, the difference between prerendering and server-side rendering, SEO and initial load improvements, and hydration and the interaction between server and client. You'll understand when SSR is needed and how to configure it.
The key concept is one application, two execution environments. The browser and the server both run the same components, but with different responsibilities.
Universal is Angular's way to render an application on the server. Setting it up is a single command:
ng add @angular/nguniversalThis command adds server.ts, a server builder in angular.json, and the dev:ssr, build:ssr, and serve:ssr scripts. The main.server.ts file becomes the server entry point, which uses renderApplication or renderModule.
import { renderApplication } from "@angular/platform-server";
import { AppComponent } from "./app/app.component";
import { appConfig } from "./app/app.config";
const bootstrap = () => import("./main").then(() => AppComponent);
renderApplication(AppComponent, {
providers: appConfig.providers,
});Development mode runs a Node server with automatic rebuilds:
npm run dev:ssrEvery file change is reflected immediately, and you can inspect the HTML sent by the server via the browser's view-source.
Prerendering turns every route into an HTML file at build time. Run the build with prerender:
ng build --prerenderThe result is a static folder that any CDN can serve. It suits pages whose content is the same for all users.
Server-side rendering produces HTML on every request, so page content can differ per user:
ng build
npm run serve:ssrserve:ssr runs the Node server from the server.ts file. Choose prerender if the page is nearly static, and SSR if the page depends on user data, session, or cookies.
A server-rendered page can inject meta tags that crawlers and social media read. Angular provides Meta and Title from @angular/platform-browser:
import { Injectable } from "@angular/core";
import { Meta, Title } from "@angular/platform-browser";
@Injectable({ providedIn: "root" })
export class SeoService {
constructor(private title: Title, private meta: Meta) {}
update(title: string, description: string): void {
this.title.setTitle(title);
this.meta.updateTag({ name: "description", content: description });
}
}With SSR, these meta tags are already in the HTML the crawler receives, so Google doesn't have to wait for JavaScript.
Users see server-rendered content faster, and the browser does less work for the first paint. Metrics like Largest Contentful Paint and time to interactive usually improve significantly.
Hydration is the process of connecting the Angular application to HTML that's already been rendered on the server. Enable it with provideClientHydration:
import { provideClientHydration } from "@angular/platform-browser";
import { ApplicationConfig } from "@angular/core";
export const appConfig: ApplicationConfig = {
providers: [provideClientHydration()],
};Once hydration is active, Angular recognizes the existing DOM, attaches event listeners, and doesn't rebuild the page from scratch. The result is no screen flicker and interactions that work right away.
A server that fetches data early can share the result with the client via TransferState, so the client doesn't fetch the same data twice:
import { TransferState, makeStateKey } from "@angular/core";
import { inject } from "@angular/core";
const CATEGORIES_KEY = makeStateKey("categories");
// di server: tulis data
// transferState.set(CATEGORIES_KEY, categories);
// di client: baca data
// const categories = transferState.get(CATEGORIES_KEY, null);This prevents the flash of empty content and double fetching, two common problems in SSR applications without TransferState.
Key takeaways:
In the next episode, episode 22, we'll cover observability and monitoring — logging frontend errors and performance metrics, monitoring user interactions, error reporting with Sentry or LogRocket, and production support and incident handling.