Getting Started with Angular Universal


Angular Universal builds on Angular‘s widespread adoption and support to provide server-side rendering and faster perceived performance to Angular applications. By pre-rendering an application at build time, or re-rendering at run time, web applications using Angular Universal benefit from better site previews, search engine optimization, and quicker page loads. Unlike traditional server-rendered strategies (JSPs, etc), Angular Universal is more of a hybrid approach. The initial page is rendered by the server, while the client-side (traditional Angular) application is loaded in the background. Once the client-side application is ready, it takes over and does all of the work from there. Therefore Angular Universal benefits from the initial load speeds of server rendering and the user experience of a client-side application. This post will illustrate the  basic usages of Angular Universal and its integration with an Angular 2 application.

Getting Started

We will begin with the starter application provided by the angular universal team. The source code can be found here. This application has Angular Universal already setup and ready to go. Prerequisites are git and node.

git clone
cd universal-starter
npm install
npm start

Navigate to http://localhost:3000 to see the running application!

Setup Explained

For the bulk of the Angular Universal configuration, visit main.node.ts

// Application
import {App} from './app/app.component';
import {routes} from './app/app.routes';
export function ngApp(req, res) {
 let baseUrl = '/';
 let url = req.originalUrl || '/';
 let config: ExpressEngineConfig = {
   directives: [
   platformProviders: [
     {provide: ORIGIN_URL, useValue: 'http://localhost:3000'},
     {provide: APP_BASE_HREF, useValue: baseUrl},
   providers: [
     {provide: REQUEST_URL, useValue: url},
   async: true,
   preboot: false
 res.render('index', config);

This is the main configuration for Angular Universal in conjunction with Express. The main application component ‘App’ is specified in the directive array. The base url http://localhost:3000 is set to the Origin with the APP_BASE_HREF set to the root of the application. This means that angular universal will take control at the root of the application rather than at a sub-path. The router is set to Angular’s default router with the client-side routes defined in app.routes.ts. Finally, async and preboot are set to true and false respectively. We will touch on their significance later.

Then, visit server.ts  to tie the Angular Universal config to the server.

import { expressEngine } from 'angular2-universal';
// Express View
app.engine('.html', expressEngine);
app.set('views', __dirname);
app.set('view engine', 'html');
import { ngApp } from './main.node';
// Routes with html5pushstate
// ensure routes match client-side-app
app.get('/', ngApp);
app.get('/about', ngApp);
app.get('/about/*', ngApp);
app.get('/home', ngApp);
app.get('/home/*', ngApp);

These two snippets from server.ts first load the Angular Universal expressEngine, then setup each of the routes with the configuration file from above. That’s all that is needed to configure Angular Universal into the application!

Page Load

Using the default server-side rendering with Angular Universal, we get the following initial page load of the starter application:


With Angular Universal, the first response will be rendered on the server. Meanwhile, the client-side application will download/bootstrap and take over when it is ready. This means that the user is immediately presented with a usable web app. Therefore, all web-crawlers, social media previews, etc. will see the fully loaded site.

After disabling Angular Universal, we get the following initial page load:


The index.html page, which shows a loading message, is shown while the client-side application downloads and bootstraps. Although a user might know to wait for the application to load, a bot might mistakenly assume that this is the fully-loaded page.


Preboot is a toggled feature of Angular Universal. When enabled, Preboot takes over during the time after the server-rendered view is displayed, but before the client-side application is fully bootstrapped. Ideally, the client-side application should handle all of the user interaction with the web application, but for a brief period of time, only the server-rendered view is available. During this time, Preboot will record all of the user’s interactions and play them back to the client-side application when it is ready. This ensures that no interactions with the web app are lost.


Another feature of Angular Universal is async. Using the power of Zone.js, Async keeps track of all the asynchronous events that occur during the server rendering, so that it can serve the page when they are all completed.


Angular Universal can provide better perceived performance for a little bit of added complexity in an Angular application. At this point Universal should only be considered by applications where initial response time or social media sharing are paramount. Angular Universal, along with most Angular 2 tools, is still in its infancy and unfortunately, the current scope of Angular Universal only applies to Angular 2 applications using a Node backend. Overall, it seems like the project is well-maintained and I believe that the documentation and adoption of Universal will continue to grow along with Angular 2.

About the Author

Object Partners profile.
Leave a Reply

Your email address will not be published.

Related Blog Posts
Natively Compiled Java on Google App Engine
Google App Engine is a platform-as-a-service product that is marketed as a way to get your applications into the cloud without necessarily knowing all of the infrastructure bits and pieces to do so. Google App […]
Building Better Data Visualization Experiences: Part 2 of 2
If you don't have a Ph.D. in data science, the raw data might be difficult to comprehend. This is where data visualization comes in.
Unleashing Feature Flags onto Kafka Consumers
Feature flags are a tool to strategically enable or disable functionality at runtime. They are often used to drive different user experiences but can also be useful in real-time data systems. In this post, we’ll […]
A security model for developers
Software security is more important than ever, but developing secure applications is more confusing than ever. TLS, mTLS, RBAC, SAML, OAUTH, OWASP, GDPR, SASL, RSA, JWT, cookie, attack vector, DDoS, firewall, VPN, security groups, exploit, […]