skip to content

Compilation & Tooling

How Angular turns decorators and templates into code, type-checks templates, and exposes runtime inspection tools. Interviewers use it to see if you know what runs between your source and the browser.

part ofAngularoverview, primer and where to startread it →
on this pageshow

explore

questions

14

In Angular, what is the difference between ahead-of-time (AoT) and just-in-time (JIT) compilation, and why is AoT the default?

level: juniorimportance: must knowfreq 62%

answer

  1. when do templates become JavaScript
  2. build machine versus the browser
  3. is @angular/compiler in the bundle
  4. the application builder's aot option

basics

~20 s

AoT compiles Angular templates into JavaScript during the build; JIT ships the Angular compiler and compiles in the browser at runtime. AoT is the default because it starts faster, ships less code and reports template errors at build time.

solid answer

~50 s

Angular templates are not JavaScript, so something must turn each `@Component` and its template into code the runtime can execute. With **JIT**, the `@angular/compiler` package is shipped to the browser and compiles every component when the app starts. With **AoT**, the compiler runs during `ng build` / `ng serve` and emits static definitions (`ɵcmp`, `ɵfac`) with template functions, so the browser downloads ready-to-run code. That removes the compiler from the bundle, skips compile work at startup, inlines external templates and styles, and surfaces template errors before users see them. AoT has been the default since Angular 9; in Angular 22.2 the CLI's application builder still defaults `aot` to `true`. JIT survives for special cases: `aot: false`, a class marked `jit: true`, the Karma builder (whose `aot` option defaults to `false`), and the runtime fallback for unlinked library code.

code

ts · 6 lines
ts
// main.ts of a non-CLI app that deliberately runs in JIT mode
import '@angular/compiler'; // must load before bootstrap in JIT mode
import { bootstrapApplication } from '@angular/platform-browser';
import { App } from './app';

bootstrapApplication(App);

go deeper

for a junior

Say where the compile step runs in each mode and name at least two AoT benefits: faster startup, no compiler in the bundle, errors caught at build time.

for a middle

Explain what AoT actually emits (static definitions with template functions) and list the places JIT still appears: aot false, jit: true, Karma defaults and unlinked library code.

for a senior

Connect JIT fallbacks to real failures: the missing @angular/compiler error in production, a library that was never linked, and why runtime template strings do not fit an AoT app.

for a principal

Frame AoT as a build-time contract: everything a template can do is known at build time, which shapes how a platform team designs dynamic or plugin-driven UI.

## Why Angular needs a compiler at all An Angular component is a TypeScript class plus a **decorator** (`@Component`) whose metadata includes an HTML-like template. Browsers understand neither the decorator metadata nor Angular's template syntax (`{{ }}`, `[prop]`, `(event)`, `@if`, `@for`). Before anything can render, the **Angular compiler** must read that metadata and produce JavaScript that creates DOM nodes and updates bindings. The only question is *where and when* that happens. ## Just-in-time (JIT): compile in the browser In **JIT** mode the application ships the `@angular/compiler` package to the browser. At startup, as each component is first needed, the runtime asks the compiler to parse its template and generate the definition on the fly. - The browser downloads the compiler as well as the framework runtime. - Every page load repeats the compilation work before the first render. - External `templateUrl` and `styleUrl` files must be fetched and compiled at runtime. - A template mistake (an unknown element, a misspelled property) surfaces only when that template is compiled in a user's browser. JIT was the default until Angular 8. ## Ahead-of-time (AoT): compile during the build In **AoT** mode the compiler runs as part of the build. For each decorated class it emits static fields such as `ɵcmp` (the component definition with a **template function** made of Ivy instructions) and `ɵfac` (the factory). The browser receives plain JavaScript that it can execute immediately. The official reasons for preferring AoT: 1. **Faster rendering** - there is no compile step between download and first paint. 2. **Fewer requests** - external templates and stylesheets are inlined into the JavaScript. 3. **Smaller download** - `@angular/compiler` is not needed at runtime, so it is not bundled. 4. **Earlier error detection** - template binding errors are reported by the build. 5. **Better security** - templates are never compiled from strings in the browser, removing a class of template-injection risk. ## Side-by-side | Aspect | JIT | AoT | | :-- | :-- | :-- | | When templates are compiled | At runtime, in the browser | At build time | | `@angular/compiler` in the bundle | Yes | No | | Template errors found | When the template is compiled at runtime | During the build | | Startup cost | Parse and compile every used component | Execute pre-built definitions | | Default | Up to Angular 8 | Since Angular 9 | ## Where JIT still appears in 2026 AoT is the norm, but a working Angular developer still meets JIT in a few places: - **`aot: false`** in a build configuration in `angular.json`. The CLI's application builder defaults `aot` to `true`, so this is an explicit opt-out. - **Karma-based tests**: the `@angular/build:karma` builder's `aot` option defaults to `false`. - **`jit: true` in a decorator**: the AoT compiler skips that class and leaves it for the runtime JIT compiler, which then must be loaded. - **Unlinked partial-Ivy library code**: a library's `ɵɵngDeclareComponent` call falls back to JIT at runtime if the build never linked it. In every JIT case the compiler must actually be present. If it is not, the runtime throws an error of the form *"The component 'X' needs to be compiled using the JIT compiler, but '@angular/compiler' is not available"*, and the message suggests adding `import '@angular/compiler';` before bootstrapping. The old `platformBrowserDynamic` entry point is deprecated in favour of `platformBrowser`, and its deprecation note says the same thing: a non-CLI JIT app must import `@angular/compiler` itself. ## What AoT does not mean - It is **not** server-side rendering. SSR renders HTML on a server; AoT only decides when templates become JavaScript, and SSR builds are AoT-compiled too. - It does **not** remove runtime work such as change detection or binding sanitization; it removes *compilation* from the runtime. - It is **not** production-only. In CLI projects `ng serve` builds from the same build target, whose `aot` defaults to `true`, so development and production run AoT-compiled output. ## A practical consequence Because an AoT build ships no compiler, you cannot take an arbitrary template string fetched at runtime and turn it into a component. Dynamic UI in an AoT app is built by choosing among components that were compiled at build time - for example with `ViewContainerRef.createComponent()` or `NgComponentOutlet` - rather than by compiling new templates in the browser.

  • What happens if an Angular app runs a JIT-compiled component but nothing loaded @angular/compiler?
    The runtime cannot find a compiler facade and throws an error saying the component needs to be compiled using the JIT compiler but `@angular/compiler` is not available. In development it also logs `JIT compilation failed` with the class. The fix is either to build with AoT or to add `import '@angular/compiler';` before bootstrapping.
  • Why can an AoT-compiled Angular app not render a component from a template string fetched at runtime?
    Because AoT removes the compiler from the bundle: templates are turned into template functions at build time and nothing in the browser can parse new template syntax. Dynamic UI is built by selecting among components that were already compiled, for example with `ViewContainerRef.createComponent()` or `NgComponentOutlet`. Shipping the JIT compiler just for this is possible but discouraged.

saying these in an interview costs you the question

  • AoT only minifies the code; templates are still compiled in the browser.
  • JIT is used for ng serve and AoT only for production builds.
  • AoT is the same thing as server-side rendering.
  • JIT has been removed from Angular and can no longer be used.
  • Template errors appear only at runtime no matter how the app is compiled.
open as a page

What can the Angular DevTools browser extension show you about a running app, and why does it refuse to work on a production build?

level: juniorimportance: must knowfreq 45%

basics

~20 s

Angular DevTools adds an Angular tab showing the component and directive tree with editable properties, the injector hierarchy with providers, and the router tree. It needs a development build, because optimized production builds strip the debug hooks it uses to talk to Angular.

open as a page

In an Angular 22 project, what does the strictTemplates compiler option check, and where is it configured?

level: juniorimportance: must knowfreq 52%

basics

~20 s

strictTemplates, set in angularCompilerOptions in tsconfig and on by default since Angular 22, makes the compiler type-check templates like TypeScript code: bindings against input types under strictNullChecks, typed $event and local references, and expressions inside embedded views.

open as a page

In Angular, what does the AoT compiler emit for a @Component class, and what are its static ɵcmp and ɵfac fields?

level: middleimportance: should knowfreq 36%

basics

~20 s

Angular's AoT compiler replaces @Component with static fields: ɵfac, a factory that creates the instance, and ɵcmp, the definition holding the selector, inputs and a template function of Ivy instructions that builds the DOM once and refreshes bindings on each check.

open as a page

From the browser console of an Angular app in development mode, how do you read and change a component's state with ng.getComponent and ng.applyChanges?

level: middleimportance: should knowfreq 32%

basics

~20 s

In development mode Angular publishes window.ng. Select the component's host element, call ng.getComponent($0) to get its instance, and change a field. A signal's set() schedules an update by itself; a plain field needs ng.applyChanges(instance) to mark it for check and run change detection.

open as a page

In Angular, what does isDevMode() return, and what actually differs between development mode and production mode at runtime?

level: middleimportance: should knowfreq 30%

basics

~20 s

Angular's isDevMode() returns true unless the app was built with script optimization or enableProdMode() was called. Development mode keeps dev-only assertions, descriptive error messages, the window.ng debug global and DevTools support; production strips them for size and speed.

open as a page

What are Angular's extended diagnostics, such as NG8101 invalidBananaInBox, and how do you change their severity?

level: middleimportance: should knowfreq 30%

basics

~20 s

Extended diagnostics are Angular compiler checks for template code that compiles but is probably wrong, like ([value]) instead of [(value)] (NG8101) or {{ count }} for a signal (NG8109). They warn by default, need strictTemplates, and are set to error, warning or suppress in angularCompilerOptions.extendedDiagnostics.

open as a page

With strictTemplates enabled in Angular, how do flags like strictInputTypes, strictNullInputTypes and strictAttributeTypes relax specific checks?

level: middleimportance: should knowfreq 38%

basics

~20 s

Each Angular strictness flag defaults to the value of strictTemplates and can be set on its own in angularCompilerOptions. Setting one to false disables only that check, such as strictNullInputTypes: false ignoring null mismatches on inputs, while the rest of strict mode stays on.

open as a page

An Angular app bundled without the Angular CLI crashes with 'JIT compilation failed' in a component from an npm library; how do partial compilation and the linker explain it?

level: seniorimportance: should knowfreq 28%

basics

~20 s

Published Angular libraries use compilationMode partial, emitting stable ɵɵngDeclare* calls instead of private Ivy instructions. The app's build must run the Angular linker to finish them; a bundler that skips it leaves a JIT fallback that fails without @angular/compiler.

open as a page

A production Angular app's error tracker shows only 'Error: NG0201' with no message; how do you read Angular's NG error codes and debug this?

level: seniorimportance: should knowfreq 36%

basics

~20 s

Angular errors carry a stable NG code; production builds strip the descriptive text, leaving only the code. Look it up at angular.dev/errors/NG0201 (no provider found), then reproduce in a development build, where the full message names the missing token and links to that page.

open as a page

After enabling strict templates, an Angular build fails because [user]="selected()" passes User | null to a required input; how do you diagnose and fix it?

level: seniorimportance: should knowfreq 46%

basics

~20 s

Angular's template checker treats the binding as an assignment under strictNullChecks, and User | null is not assignable to User. Render the child only when a user exists, or let the input accept null; reserve ! and $any() for values you can prove are set.

open as a page

What does the Angular Language Service add to a code editor, and why does it work best with strictTemplates enabled?

level: juniorimportance: nice to knowfreq 22%

basics

~20 s

The Angular Language Service gives editors template intelligence: completions, the compiler's own diagnostics, quick info on hover and go-to-definition, for inline and external templates. It reads tsconfig, so with strictTemplates it sees precise template types and gives the most accurate results.

open as a page

What is the Angular Ivy compiler's locality principle, and why does it require decorator metadata to be statically analyzable?

level: middleimportance: nice to knowfreq 24%

basics

~20 s

Locality means the Angular compiler builds each class's definition from its own decorator plus the declared shape of what it uses. Since no code runs at build time, decorator arguments must be object literals the compiler can evaluate statically.

open as a page

When writing a custom Angular structural directive, what do the static ngTemplateGuard_ and ngTemplateContextGuard members tell the template type checker?

level: seniorimportance: nice to knowfreq 18%

basics

~20 s

They are compile-time hints for Angular's template type checker. ngTemplateGuard_<input> narrows the bound expression inside the directive's template, via a type predicate or the literal 'binding' for truthiness; ngTemplateContextGuard declares the template context's type so let- variables get real types.

open as a page