This page describes tools and techniques for deploy and optimize your Angular application.
Table of contents
- Simplest deployment possible
- Optimize for production
- Angular configuration
- Server configuration
This guide describes techniques for preparing and deploying an Angular application to a server running remotely. The techniques progress from easy but suboptimal to more optimal and more involved.
The simple way is to copy the development environment to the server.
Webpack is a popular general purpose packaging tool with a rich ecosystem, including plugins for AOT. The Angular webpack guide can get you started and this page provides additional optimization advice, but you'll probably have to learn more about webpack on your own.
The Angular configuration section calls attention to specific client application changes that could improve performance.
The Server configuration section describes server-side changes that may be necessary, no matter how you deploy the application.
Simplest deployment possible
The simplest way to deploy the app is to publish it to a web server directly out of the development environment.
It's already running locally. You'll just copy it, almost as is, to a non-local server that others can reach.
Copy everything (or almost everything) from the local project folder to a folder on the server.
If you're serving the app out of a subfolder, edit a version of
index.htmlto set the
<base href>appropriately. For example, if the URL to
www.mysite.com/my/app/, set the base href to
<base href="/my/app/">. Otherwise, leave it alone. More on this below.
Configure the server to redirect requests for missing files to
index.html. More on this below.
Enable production mode as described below (optional).
That's the simplest deployment you can do.
This is not a production deployment. It's not optimized and it won't be fast for users. It might be good enough for sharing your progress and ideas internally with managers, teammates, and other stakeholders. Be sure to read about optimizing for production below.
Load npm package files from the web (SystemJS)
node_modules folder of npm packages contains much more code
than is needed to actually run your app in the browser.
node_modules for the Quickstart installation is typically 20,500+ files and 180+ MB.
The application itself requires a tiny fraction of that to run.
It takes a long time to upload all of that useless bulk and users will wait unnecessarily while library files download piecemeal.
Load the few files you need from the web instead.
(1) Make a copy of
index.html for deployment and replace all
with versions that load from the web. It might look like this.
(2) Replace the
systemjs.config.js script with a script that
systemjs.config.server.js (shown in the code sample below) to the
This alternative version configures SystemJS to load UMD versions of Angular
(and other third-party packages) from the web.
systemjs.config.server.js as necessary to stay in sync with changes
you make to
In the standard SystemJS config, the
npm path points to the
In this server config, it points to
a site that hosts npm packages,
and loads them from the web directly.
There are other service providers that do the same thing.
If you are unwilling or unable to load packages from the open web,
the inventory in
systemjs.config.server.js identifies the files and folders that
you would copy to a library folder on the server.
Then change the config's
'npm' path to point to that folder.
Practice with an example
The following trivial router sample app shows these changes.
Practice with this sample before attempting these techniques on your application.
Follow the setup instructions for creating a new project named
Add the "Simple deployment" sample files shown above.
Run it with
npm startas you would any project.
Inspect the network traffic in the browser developer tools. Notice that it loads all packages from the web. You could delete the
node_modulesfolder and the app would still run (although you wouldn't be able to recompile or launch
lite-serveruntil you restored it).
Deploy the sample to the server (minus the
When you have that working, try the same process on your application.
Optimize for production
Although deploying directly from the development environment works, it's far from optimal.
The client makes many small requests for individual application code and template files, a fact you can quickly confirm by looking at the network tab in a browser's developer tools. Each small file download can spend more time communicating with the server than tranfering data.
Development files are full of comments and whitespace for easy reading and debugging. The browser downloads entire libraries, instead of just the parts the app needs. The volume of code passed from server to client (the "payload") can be significantly larger than is strictly necessary to execute the application.
The many requests and large payloads mean the app takes longer to launch than it would if you optimized it. Several seconds may pass (or worse) before the user can see or do anything userful.
Does it matter? That depends upon business and technical factors you must evaluate for yourself.
If it does matter, there are tools and techniques to reduce the number of requests and the size of responses.
- Ahead-of-Time (AOT) Compilation: pre-compiles Angular component templates.
- Bundling: concatenates modules into a single file (bundle).
- Inlining: pulls template html and css into the components.
- Minification: removes excess whitespace, comments, and optional tokens.
- Uglification: rewrites code to use short, cryptic variable and function names.
- Dead code elimination: removes unreferenced modules and unused code.
- Pruned libraries: drop unused libraries and pare others down to the features you need.
- Performance measurement: focus on optimizations that make a measurable difference.
Each tool does something different. They work best in combination and are mutually reinforcing.
You can use any build system you like. Whatever system you choose, be sure to automate it so that building for production is a single step.
Ahead-of-Time (AOT) compilation
The Angular Ahead-of-Time compiler pre-compiles application components and their templates during the build process.
Apps compiled with AOT launch faster for several reasons.
- Application components execute immediately, without client-side compilation.
- Templates are embedded as code within their components so there is no client-side request for template files.
- You don't download the Angular compiler, which is pretty big on its own.
- The compiler discards unused Angular directives that a tree-shaking tool can then exclude.
Learn more about AOT Compilation in the AOT Cookbook which describes running the AOT compiler from the command line and using rollup for bundling, minification, uglification and tree shaking.
Webpack (and AOT)
Webpack 2 is another great option for inlining templates and style-sheets, for bundling, minifying, and uglifying the application. The "Webpack: an introduction" guide will get you started using webpack with Angular.
Consider configuring Webpack with the official
Angular Ahead-of-Time Webpack Plugin.
This plugin transpiles the TypeScript application code,
bundles lazy loaded
and performs AOT compilation — without any changes to the source code.
Dead code elimination with rollup
Any code that you don't call is dead code. You can reduce the total size of the application substantially by removing dead code from the application and from third-party libraries.
Tree shaking was popularized by Rollup, a popular tool with an ecosystem of plugins for bundling, minification, and uglification. Learn more about tree shaking and dead code elmination in this post by rollup-creator, Rich Harris.
Don't count on automation to remove all dead code.
Remove libraries that you don't use, especially unnecessary scripts in
Consider smaller alternatives to the libraries that you do use.
Some libraries offer facilities for building a custom, skinny version with just the features you need.
Other libraries let you import features a la carte.
RxJS is a good example; import RxJS
Observable operators individually instead of the entire library.
Measure performance first
You can make better decisions about what to optimize and how when you have a clear and accurate understanding of what's making the application slow. The cause may not be what you think it is. You can waste a lot of time and money optimizing something that has no tangible benefit or even makes the app slower. You should measure the app's actual behavior when running in the environments that are important to you.
The Chrome DevTools Network Performance page is a good place to start learning about measuring performance.
The WebPageTest tool is another good choice that can also help verify that your deployment was successful.
Angular configuration can make the difference between whether the app launches quickly or doesn't load at all.
The HTML <base href="..."/>
specifies a base path for resolving relative URLs to assets such as images, scripts, and style sheets.
For example, given the
<base href="/my/app/">, the browser resolves a URL such as
into a server request for
During navigation, the Angular router uses the base href as the base path to component, template, and module files.
See also the APP_BASE_HREF alternative.
In development, you typically start the server in the folder that holds
That's the root folder and you'd add
<base href="/"> near the top of
/ is the root of the app.
But on the shared or production server, you might serve the app from a subfolder.
For example, when the URL to load the app is something like
the subfolder is
my/app/ and you should add
<base href="/my/app/"> to the server version of the
base tag is misconfigured, the app fails to load and the browser console displays
404 - Not Found errors
for the missing files. Look at where it tried to find those files and adjust the base tag appropriately.
Enable production mode
Angular apps run in development mode by default, as you can see by the following message on the browser console:
Switching to production mode can make it run faster by disabling development specific checks such as the dual change detection cycles.
To enable production mode when running remotely, add the following code to the
You can dramatically reduce launch time by only loading the application modules that absolutely must be present when the app starts.
Configure the Angular Router to defer loading of all other modules (and their associated code), either by waiting until the app has launched or by lazy loading them on demand.
Don't eagerly import something from a lazy loaded module
It's a common mistake.
You've arranged to lazy load a module.
in a file that's eagerly loaded when the app starts, a file such as the root
If you do that, the module will be loaded immediately.
Angular Ahead-of-Time Webpack Plugin
automatically recognizes lazy loaded
NgModules and creates separate bundles for them.
This section covers changes you may have make to the server or to files deployed to the server.
Routed apps must fallback to
Angular apps are perfect candidates for serving with a simple static HTML server. You don't need a server-side engine to dynamically compose application pages because Angular does that on the client-side.
If the app uses the Angular router, you must configure the server
to return the application's host page (
index.html) when asked for a file that it does not have.
A routed application should support "deep links".
A deep link is a URL that specifies a path to a component inside the app.
http://www.mysite.com/heroes/42 is a deep link to the hero detail page
that displays the hero with
There is no issue when the user navigates to that URL from within a running client. The Angular router interprets the URL and routes to that page and hero.
But clicking a link in an email, entering it in the browser address bar, or merely refreshing the browser while on the hero detail page — all of these actions are handled by the browser itself, outside the running application. The browser makes a direct request to the server for that URL, bypassing the router.
A static server routinely returns
index.html when it receives a request for
But it rejects
http://www.mysite.com/heroes/42 and returns a
404 - Not Found error unless it is
configured to return
Fallback configuration examples
There is no single configuration that works for every server. The following sections describe configurations for some of the most popular servers. The list is by no means exhaustive, but should provide you with a good starting point.
Webpack-Dev-Server: setup the
historyApiFallbackentry in the dev server options as follows:
- NGinx: use
try_files, as described in Front Controller Pattern Web Apps, modified to serve
GitHub Pages: you can't directly configure the GitHub Pages server, but you can add a 404 page. Copy
404.html. It will still be served as the 404 response, but the browser will process that page and load the app properly. It's also a good idea to serve from
docs/on master and to create a
Requesting services from a different server (CORS)
Angular developers may encounter a cross-origin resource sharing error when making a service request (typically a data service request). to a server other than the application's own host server. Browsers forbid such requests unless the server permits them explicitly.
There isn't anything the client application can do about these errors. The server must be configured to accept the application's requests. Read about how to enable CORS for specific servers at enable-cors.org.
If you want to go beyond the simple copy-deploy approach, read the AOT Cookbook next.