skip to content

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%

answer

  1. the decorator becomes static fields
  2. a factory and a definition
  3. template function with two modes
  4. create block, then update block

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.

solid answer

~40 s

AoT turns decorator metadata into **static definitions** on the class. `ɵfac` is the factory the runtime calls to create an instance (with its dependencies resolved). `ɵcmp` is produced by `ɵɵdefineComponent` and carries the `selectors`, inputs and outputs, the `decls`/`vars` counts used to size the view's data array, the component's dependencies, and a **template function**. That function takes render flags: the `rf & 1` block runs once and creates nodes with instructions such as `ɵɵelementStart`, `ɵɵtext` and `ɵɵelementEnd`; the `rf & 2` block runs on every check and updates bindings with `ɵɵadvance`, `ɵɵproperty` or `ɵɵtextInterpolate1`. Directives get `ɵdir`, pipes `ɵpipe`, injectables `ɵprov`, NgModules `ɵmod` and `ɵinj`. The `ɵ` prefix marks private, unstable API: application code never calls these directly.

code

ts · 6 lines
ts
import { Component } from '@angular/core';

@Component({ selector: 'app-greeting', template: '<div>Hello {{ name }}</div>' })
export class Greeting {
  name = 'World';
}

go deeper

for a junior

Know that AoT turns the decorator into generated code and that the template becomes a JavaScript function rather than an HTML string.

for a middle

Name ɵfac and ɵcmp, explain the create and update passes of the template function, and say why the ɵ prefix means private API.

for a senior

Use this model to read a production stack trace into a Component_Template function and to explain why unused Ivy features are tree-shaken away.

for a principal

Weigh the tradeoff Ivy made: generated code that is private and version-bound, in exchange for tree-shaking and cheap updates, and what that implies for publishing libraries.

## From decorator to static definition In source, a component is a class with a `@Component({...})` decorator. The Angular AoT compiler reads that decorator at build time and rewrites the class so the runtime never needs the decorator at all. What remains is ordinary JavaScript with a few **static fields**, each holding a *definition* the runtime reads. | Field | Emitted for | Holds | | :-- | :-- | :-- | | `ɵfac` | every decorated class | the **factory**: creates an instance and resolves its dependencies | | `ɵcmp` | `@Component` | the **component definition**: selector, inputs, outputs, template function, styles, dependencies | | `ɵdir` | `@Directive` | the directive definition (a component definition without a template) | | `ɵpipe` | `@Pipe` | the pipe definition: name, purity | | `ɵprov` | `@Injectable` | how an injector creates the service and where it is provided | | `ɵmod` / `ɵinj` | `@NgModule` | the module's compilation scope and its injector configuration | The `ɵ` (theta) prefix marks these as private, code-generation API. They are not part of Angular's public contract and can change between versions, which is exactly why published libraries do not ship them directly. ## What is inside `ɵcmp` `ɵcmp` is created by calling `ɵɵdefineComponent({...})` (wrapped in a `/*@__PURE__*/` annotation so bundlers can drop unused components). Its main properties: - **`type`** - the component class itself. - **`selectors`** - the parsed CSS selector, such as `[['app-greeting']]`. - **inputs and outputs** - which class members are bindable. - **`decls`** - the number of nodes, local references and pipes in the template; the runtime uses it to size the view's data array (the `LView`). - **`vars`** - the number of binding slots, which sets where binding values are stored for comparison. - **`consts`** - static attribute arrays and similar data shared across instances. - **`template`** - the **template function**. - **`dependencies`** - the components, directives and pipes the template may use. ## The template function and its two passes The template becomes a function `(rf, ctx) => ...`, where `ctx` is the component instance and `rf` is a set of **render flags**: 1. **Create pass (`rf & 1`)** - runs once per view instance. Instructions such as `ɵɵelementStart(0, 'div')`, `ɵɵtext(1)` and `ɵɵelementEnd()` create DOM nodes and store them in numbered slots. Event listeners are registered here too. 2. **Update pass (`rf & 2`)** - runs on every change detection check of that view. `ɵɵadvance()` moves a cursor to the next slot that has bindings, and instructions such as `ɵɵproperty('value', ctx.name)` or `ɵɵtextInterpolate1('Hello ', ctx.name)` compare the new value with the stored one and touch the DOM only when it differs. This split is what makes Ivy's update path cheap: nodes are created once, and each check is a linear walk of binding instructions. ## Why instructions instead of an interpreted template - **Tree-shaking**: every instruction is an exported function of `@angular/core`. A template that never uses, say, i18n or pipes never references those instructions, so the bundler can drop their code. - **No runtime parsing**: the browser executes plain functions rather than parsing template syntax. - **Readable output**: the generated code maps line-for-line onto the template, which helps when debugging a production stack trace that points into `Greeting_Template`. ## `ɵfac` and dependency injection `ɵfac` is a small function that constructs the class, for example `function Greeting_Factory(t) { return new (t || Greeting)(); }`. For constructor injection the compiler emits the `ɵɵdirectiveInject` or `ɵɵinject` calls for each parameter; for `inject()` in a field initializer, the factory simply runs the constructor inside an **injection context** so those calls can resolve. ## What happens to the decorator metadata In a full AoT build the original decorator arguments survive only inside a call to `ɵsetClassMetadata`, guarded by `ngDevMode`. Development tooling and `TestBed` overrides can read it; production builds strip it with the rest of the dev-mode code. No `.metadata.json` files are produced: those belonged to the pre-Ivy View Engine compiler. ## How to explain it in an interview - Start from the **decorator becoming data**: static definitions on the class that the runtime reads. - Name the two you meet most: `ɵfac` creates, `ɵcmp` describes and renders. - Describe the **two passes** of the template function and why the update pass is cheap. - Close with the caveat: all of it is private, generated API that you read while debugging but never write or call.

  • Why do Angular's generated fields and instructions start with ɵ, and may application code call them?
    The `ɵ` prefix marks private, code-generation API. It is not covered by Angular's public-API guarantees and can change even between patch releases. Application code should use public APIs such as `inject()`, `createComponent()` or `reflectComponentType()` instead of reading `ɵcmp` or calling `ɵɵ` instructions.
  • What do decls and vars in an Angular ɵcmp tell the runtime?
    `decls` counts the template's nodes, local references and pipes; `vars` counts its binding slots. Together they size the view's data array up front, so the runtime can pre-allocate it and know where binding values start. Both are computed by the compiler; nobody writes them by hand.

The decorator is a recipe card; AoT cooks it in the kitchen before service. The create block is plating the dish once, and the update block is only swapping the garnish when the order changes.

saying these in an interview costs you the question

  • The template is shipped as an HTML string and parsed in the browser.
  • ɵcmp is a public API that application code can rely on.
  • The update block recreates the DOM nodes on every change detection run.
  • ɵfac is the component definition that holds the template function.
  • AoT still writes a .metadata.json file for every component.