skip to content

Ahead-of-Time Compiler

The AoT compiler turns each decorated class and its template into Ivy instructions and static definitions like ɵcmp, file by file. Interviewers probe AoT vs JIT and partial compilation for libraries.

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

explore

questions

4

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

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

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

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