Skip to content

What's new in Angular v12

🔗Angular 12 Released

Angular v12 has been released! Here are some main updates.

🔗Nullish coalescing operator support

  selector: 'app-comp',
  template: `<div>Hello, {{title ?? 'Angular'}}</div>`


🔗APP_INITIALIZER now supports Observable.

It is also a long-waited feature request: in Angular v12, we can now use Observable as APP_INITIALIZER.

import { APP_INITIALIZER } from '@angular/core';

function observableInitializer() {
  // Before Angular v12, you have to return a Promise.
  // return () => someObservable().toPromise();
  // Now you can return the observable directly.
  return () => someObservable();

  imports: [...],
  providers: [{
    provide: APP_INITIALIZER,
    useFactory: observableInitializer,
    multi: true
export class AppModule {}



Before Angular 12, if you wanted to pass boolean or number as HttpParams, you had to:

HttpClient.get('api/endpoint', { param1: '10', param2: 'true' })

With Angular 12, the HttpParams has been updated to accept the boolean and the number values:

HttpClient.get('api/endpoint', { param1: 10, param2: true })

🔗Http Interceptor Context

This is a very long waited feature. In Angular 12, you can now pass data between interceptors. Here is a great article by Netanel Basal.

🔗More readable Http status code

An enum HttpStatusCode is provided, so the user can use this enum to write more readable code for status code check.'api/endpoint', postBody, {observe: 'response'}).subscribe(res => { if (res.status === HttpStatusCode.Ok) { ... } });


🔗Form: Support min/max validator

HTML5 standards support built in validator such as min/max for input element.

<input type="number" min="5" max="10">

Before Angular 12, the min/max attributes are ignored by FormsModule, so the Angular FormControl valid property will still be true even the input data exceed the min or max range. But the underlying DOM HTMLInputElement's validity.valid will still be false.

From Angular 12, the min/max validator is implemented so the valid result will be consistent with native DOM status.


Sometimes we want to disable animations. Before Angular 12, we needed to provide the NoopAnimationModule. In Angular 12, there is a new way to do that by using BrowserAnimationsModule.withConfig({disableAnimations: true}) so the user can disable animations based on the runtime information.


🔗Router: Support location.historyGo() functionality.

Support location.historyGo(relativePosition: number) to navigate to the specific history page so it will be compatible with the DOM history.go() API.

🔗Router: Provides RouterOutletContract interface

Provides RouterOutletContract interface allows the 3rd party library to implement its own RouterOutlet more easily (such as add own logic for navigation, animation). For details, please refer to this PR


🔗Angular Linker

Ivy has been released from Angular 9 and has become the default in the Angular App from Angular 10. It is fast, easy to debug, and has a lot of possibilities in the future. However, for Angular library development, the user still has to compile the lib with the old ViewEngine to publish to npm. The Angular library deploy process is:

  1. The developer compiles the lib with ViewEngine.
  2. When the Angular app is using the lib, when yarn install, Angular compiler will travel the node_modules directory and use ngcc to convert the ViewEngine library to Ivy. This process is slow and needs to run whenever node_modules changes.

The reason we need this process is if we remove ngcc and publish the Ivy instructions to npm, the instruction code will become the public API. It is very difficult to change it in the future. ViewEngine is not instruction but metadata, so it can be used across multiple versions even for Ivy.

To resolve this issue, Angular provides an RFC last year,, with an idea which is Angular Linker. It is an advanced version ngcc. It compiles the Angular library code with partial mode.

  • The output is not Ivy instructions, so it allows future changes.
  • The output is still metadata, but not like ViewEngine, the metadata is self-contained, so the output for one component contains all the information needed to compile this component without any other global knowledge(such as NgModule). It is fast and be able to do incremental/cache/parallel build.
  • The new intermediate output can be directly consumed by Angular Compiler, so the node_modules folder doesn't need to be touched.

To use this feature, update the option in the like this.

"enableIvy": "true", "compilationMode": "partial"

🔗Typescript 4.2 support

  • Supports Typescript 4.2.

🔗E2E protractor RFC

Angular is using protractor for e2e test. The protractor has a long history from 2013. It helped users write e2e test, and to support better async test, protractor did a lot of work via ControlFlow to make async/await work.

Since the native async/await is introduced into Javascript standard, protractor ControlFlow becomes incompatible with the native async/await, so protractor drops the ControlFlow and uses the solution of selenium-webdriver completely.

Also protractor has a lot of features just for AngularJS such as locator/mock. After removing these codes, protractor becomes a wrapper of selenium wrapper without any valuable functionalities.

And now the Angular developers are using several alternative solutions to do the e2e test such as:

  • Cypress
  • PlayWright
  • Puppeteer

The Angular team posts an RFC to deprecate the protractor and make Angular easy to integrate with the 3rd party e2d platform.

Here is the RFC

Based on the RFC, Angular plans to drop the protractor support until Angular v15 and will guide the Angular developers to select an alternative platform when the user tries to run ng e2e.

🔗CLI: Webpack 5 support

Webpack 5 support many new features such as:

  • Module federation is a new way to develop micro-frontend
  • Disk caching for faster build
  • Better tree shaking

🔗CLI: Lint

Angular v11 deprecated to use TSLint as the default linter, and Angular v12 remove TSLint and codelyzer from cli, so please reference the following article to migrate to eslint. (

🔗CLI: Build

When we build an Angular app, we use ng build --prod all the time. The options often confuse the user that --prod will make a production build, but it is just an alias of ng build --configuration=production. To make this more clear, CLI remove --prod and add a defaultConfiguration setting with the value production. Now, ng build default will build with production configuration.

🔗CLI: Build bundles with ES2017+

Until Angular 12, Angular only supports output bundles in ES2015 format. ES2017+ is not supported because Zone.js is not supporting native async/await patching. From Angular 12, CLI supports to only transpile the native async/await code to Promise but keep the other ES2017+ code untouched, so you can specify the output bundle format to ES2017+ from Angular 12.

🔗CLI: inlineCritical by default

The inlineCritical settings of styles optimization in the angular.json becomes true by default. Please reference here for more details.

🔗CLI: strict mode by default

The workspace generated by CLI will use strict mode by default. To generate non-strict mode, use --no-strict option.

🔗CLI: Built in tailwindcss support

Tailwindcss is a popular CSS library. Before Angular 12, to integrate with Tailwindcss, the user needs to do some postcss configuration themselves. With Angular 12, this is done by the CLI so it is super easy to do the integration.

npm install -D tailwindcss npx tailwindcss init

This is the same process to install the normal Tailwindcss.

🔗CLI: confirm ng add before install packages from npm.

Now ng add will ask the user to confirm the package/version before installing the packages. This gives the user a chance to stop the process when the user has a typo in the project name or want to initialize the project with other options.

🔗Angular Language Service for Ivy

Angular Ivy has been released since v9, but the Angular Language Service is still using View Engine to compile the template and did a lot of magic work to make everything work in Ivy, which is not efficient. Also, since View Engine is deprecated, some issues and features may not be implemented in the View Engine version of Language Service for Ivy.

Now we have the new Angular Language Service written in Ivy and for Ivy.

You can opt-in the new Angular Language Service beta with Ivy support now. To use it in VSCode, try the following steps.

  1. Install the latest extension in the VSCode Marketplace
  2. Set strictTemplates: true in tsconfig.json Angular compiler options
  3. Go to Preferences -> Settings -> Extensions -> Angular Language Service -> Check “Experimental Ivy”

Please reference this blog for more details.

🔗CLI: Support inlineStyleLanguage option

A new build option inlineStyleLanguage is added. Now you can write css/sass/scss/less in the inline style of a component!

🔗Angular Components

🔗MDC Web based new component

Angular Component is continuing to create new MDC Web based components and the backward-compatible. Here is the design.

Angular Component MDC Web

For the new Angular Material Component, Angular CDK provides the behavior and the MDC Web Component provides the user experiences defined by the Material Design spec. The Angular Material team doesn't need to maintain another implementation of the Material Design and the UI will be more consistent.

🔗New @use SASS module system

You may already use the @import syntax in the SASS style file, but it has some flaws and make the module system hard to maintain. For details, please reference the article here.

Now Angular Components are using the new @use syntax for the better module system of SASS. To use the new module system, you can use the following schematic to migrate.

ng g @angular/material:themingApi

Also, the node-sass package will be replaced by the new sass package.


  • IE11 support is deprecated!
  • ViewEngine for application build is removed. All applications are using Ivy to build.
  • entryComponent is removed from Component schematic.
  • string based lazy loading support is dropped.

{ path: 'Lazy', component: LazyComponent }, { path: 'lazy', loadChildren: './modules/lazy/lazy.module#LazyModule', }

is not supported, please use dynamic import instead.

{ path: 'Lazy', component: LazyComponent }, { path: 'lazy', loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule) }

For the full deprecation list, please check here.

🔗How to update to v12

Use the Angular CLI:

ng update @angular/cli @angular/core

You can find more information from

This Dot Labs is a modern web consultancy focused on helping companies realize their digital transformation efforts. For expert architectural guidance, training, or consulting in React, Angular, Vue, Web Components, GraphQL, Node, Bazel, or Polymer, visit

This Dot Media is focused on creating an inclusive and educational web for all. We keep you up to date with advancements in the modern web through events, podcasts, and free content. To learn, visit

You might also like


Internationalization (I18N) in Angular with Transloco


Angular v10 released!


Make it Accessible: Better Layout with HTML


Make it Accessible: Accessible Alphabet Board with Angular and RxJs