Introduction to server-side rendering with Angular

Alain Chautard
Angular Training
Published in
5 min readJan 10, 2024

--

Angular logo streaming server-side code to a browser — an AI-generated image edited by yours truly

In this post, I cover how to do server-side rendering (SSR) with Angular, why and when it matters, and everything you need to know to get started.

Why server-side rendering (SSR)?

There are a few good reasons to use SSR:

  1. Make your application faster: If your app has a lot of static content that is always the same (not user-specific), it makes sense to have that content built on the server side and returned to all users because the server can (and will) cache that content, which prevents rebuilding that HTML over and over again.
  2. Search engine optimization (SEO): Google has become good with indexing Javascript-generated content. However, at times, a pre-rendered page can load faster and thus get favored by the SEO gods.
  3. Better performance: SSR results in better Lighthouse scores for First Contentful Paint (FCP), Largest Contentful Paint (LCP), as well as Cumulative Layout Shift (CLS) because the content of the page and its layout are there from the get-go and remain stable. This is important because some devices (older smartphones) can struggle with web pages when their content is moving around while loading.
Angular Certification Exam

How do you do server-side rendering?

With Angular 17, it has become super easy. If you create a new project, just run:

ng new --ssr

If you want to add SSR to an existing project, just run the following:

ng add @angular/ssr

And that’s it! There’s a catch: Once you use Angular for SSR, you need a Node.js server to run your Angular server-side code.

In other words, the server-side code is generated for you, but you need a server capable of running it, which is different from a regular Angular application.

Here are the additional files containing the server code:

What happens when we use server-side rendering?

When we use server-side rendering, Angular pre-renders our “pages” on the server side. We can see that from the browser, where instead of receiving the near empty index.html you’re probably familiar with:

<!doctype html>
<html lang="en">
<head>
...
</head>
<body>
<app-root></app-root>
</body>
</html>

We can see the entire HTML being downloaded right from the start in the browser dev tools — before any Javascript is downloaded:

That’s because the server-side app has run any request from HttpClient, cached that data, and sent it to the browser along with the HTML of the page. Angular can reuse that data on the client side, which means HTTP requests to get data from an API do not have to run twice.

On the client side, once the pre-rendered HTML is downloaded, Angular takes over updating the DOM through hydration.

Instead of rebuilding the entire app in the browser (which was the case in the past), hydration allows Angular to reuse the server-generated DOM structure for a seamless transition to our Javascript code. It’s all automatic; we don’t need to do anything. Hydration is enabled by default on band-new Angular SSR projects:

export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideClientHydration()
t]
};

Are there any caveats to be aware of?

Yes, there are a few. Browser-specific global objects like window, document, navigator, or location as well as specific properties of HTMLElement are not available on the server side since there’s no browser there.

If you need to use those, you have to call that code in the brand-new afterRender and afterNextRender lifecycle methods as illustrated here:

export class MyComponent {

@ViewChild('content') contentRef: ElementRef;

constructor() {

afterNextRender(() => {
// Safe to check `scrollHeight` because this will only run
// in the browser, not the server.
console.log(this.contentRef.nativeElement.scrollHeight);
});
}

}
Weekly Angular Newsletter Subscription Link

What if I don’t want or can’t use a Node.js server?

Here is some good news: You can use those same features to pre-render the application on the server at build time, then use those pre-rendered pages as a full client-side Angular app, which doesn’t need a Node.js server!

To do so, you would build your Angular SSR app with ng build, automatically creating pre-rendered HTML files for all your routes.

For instance, with a routing config of:

export const routes: Routes = [
{path: "fun", component: FunComponent},
{path: "hello", component: HelloComponent}
];

With SSR, the Angular ng build command creates the following file structure in the dist folder:

Pre-rendered HTML pages

As you can see, index.html files have been created for my two routed components and the main AppComponent. We have three different HTML files, one for each component.

We can deploy those static files to our HTTP server and enjoy the benefits of pre-rendering, also known as static site generation (SSG) at minimal cost since we don’t have to change our server infrastructure.

How cool is that?

Quick Angular Updates (not SSR related)

The Angular team has published the results of its annual developer survey. I was surprised to learn that 96% of developers already use standalone components.

If you want to provide feedback and help shape my newsletter content for 2024, you can also fill out the Weekly Angular Newsletter feedback form.

My name is Alain Chautard. I am a Google Developer Expert in Angular and a consultant and trainer at Angular Training, where I help web development teams learn and become comfortable with Angular.

If you enjoyed this article, please clap for it or share it. Your help is always appreciated. You can also subscribe to my articles and the Weekly Angular Newsletter for helpful Angular tips, updates, and tutorials.

--

--