Open-Source Wikis

/

Angular

/

Angular

/

Architecture

angular/angular

Architecture

Angular ships several distinct artifacts from a single monorepo: the @angular/* runtime packages on npm, the angular.dev documentation site, the Angular DevTools browser extension, and the framework's own development app. Bazel is the build orchestrator across all of them, with pnpm workspaces handling JavaScript dependency resolution.

High-level layers

graph TD
  subgraph Authoring
    Templates["Templates<br/>(.html, inline)"]
    TS["TypeScript classes<br/>@Component / @Directive / @Pipe"]
  end

  subgraph CompileTime["Compile time (ngtsc)"]
    NgTsc["packages/compiler-cli/src/ngtsc<br/>Annotation handlers"]
    NgCompiler["packages/compiler<br/>Template parser → IR → output"]
  end

  subgraph RunTime["Runtime (Ivy)"]
    Core["packages/core/src/render3<br/>LView, TView, instructions"]
    DI["packages/core/src/di<br/>Hierarchical injectors"]
    CD["Change detection<br/>(zoneless capable)"]
    Signals["@angular/core/primitives/signals<br/>Reactivity primitives"]
  end

  subgraph Platform["Platform"]
    PB["platform-browser<br/>(DOM renderer)"]
    PS["platform-server<br/>(SSR renderer + domino)"]
  end

  subgraph Domain["Domain libraries"]
    Common["@angular/common<br/>(NgIf, NgFor, NgForOf, HttpClient)"]
    Router["@angular/router"]
    Forms["@angular/forms<br/>(reactive + signal forms)"]
    Animations["@angular/animations"]
    Elements["@angular/elements"]
  end

  Templates --> NgTsc
  TS --> NgTsc
  NgTsc --> NgCompiler
  NgCompiler --> Core
  Core --> CD
  Core --> DI
  Core --> Signals
  CD --> PB
  CD --> PS
  Domain --> Core

The compile-time pipeline (ngtsc)

ngtsc is the TypeScript compiler plugin Angular ships in packages/compiler-cli/src/ngtsc. It is a TypeScript transformer that:

  1. Reads each source file via ts.Program.
  2. Discovers Angular decorators (@Component, @Directive, @Pipe, @Injectable, @NgModule) using annotation handlers under ngtsc/annotations/.
  3. Resolves component templates (inline or templateUrl) and stylesheets via ngtsc/resource.
  4. Hands templates to the @angular/compiler parser, which produces the template AST and the intermediate representation (IR) defined in packages/compiler/src/render3/view.
  5. Emits Ivy "definition" output: a ɵcmp static field on the component class that contains the compiled template instructions, plus diagnostics for type-checked templates.
  6. Optionally writes a .d.ts augmentation so downstream consumers see the public API.

Two related entry points live next to it:

Type checking of templates is performed by the typecheck subsystem (ngtsc/typecheck), which generates "type check blocks" (TCBs) — synthetic TypeScript statements that mirror template binding semantics so that tsc can produce ordinary diagnostics.

The Ivy runtime

packages/core/src/render3 is the Ivy runtime: instruction-based, tree-shakable, and the engine since Angular 9. The two key data structures are LView and TView:

  • TView (template view, in render3/interfaces/view.ts) — the static, compile-time-derived blueprint shared across all instances of a component.
  • LView — the per-instance live array containing component context, bindings, child views, and DOM references.

A compiled template is a function over LView that calls instructions like ɵɵelementStart, ɵɵproperty, ɵɵtemplate, ɵɵtext, ɵɵlistener, etc. The instruction set lives in packages/core/src/render3/instructions.

sequenceDiagram
  participant Bootstrap as bootstrapApplication
  participant Core as @angular/core
  participant Tmpl as Compiled template fn
  participant DOM
  Bootstrap->>Core: createComponent(rootDef)
  Core->>Core: allocate LView, link to TView
  Core->>Tmpl: render(LView, RenderFlags.Create)
  Tmpl->>DOM: ɵɵelementStart, ɵɵtext, ...
  Core->>Tmpl: render(LView, RenderFlags.Update)
  Tmpl->>DOM: ɵɵproperty(value)

Change detection drives subsequent updates: markForCheck schedules a tick, the scheduler runs refreshView over each dirty LView, and instructions in RenderFlags.Update mode re-evaluate bindings. Signals add a finer-grained reactive layer in packages/core/primitives/signals: components that read signals automatically subscribe via a ReactiveLViewConsumer and are scheduled when the signal changes, even in zoneless apps.

Dependency injection

Hierarchical injectors are implemented in packages/core/src/di with the runtime hot path in render3/di.ts. Each LView carries a bloom-filter–accelerated lookup so directive injection at template instantiation time stays O(1) on average. Provider scopes — module, environment, component, and platform — are layered as separate injector trees that delegate upward.

Platform abstraction

The DOM is abstracted behind a Renderer2 interface so that the same template instructions can run on different platforms:

Hydration (packages/core/src/hydration) reuses the SSR-produced DOM at boot time instead of destroying and re-creating it, including support for incremental hydration of deferred views.

Build orchestration: Bazel + pnpm

Bazel is the source of truth for build graphs. Top-level BUILD.bazel files in each package describe TypeScript libraries (ng_module), tests (ng_web_test_suite, nodejs_test), and bundles. pnpm-workspace.yaml enumerates the JavaScript projects so that workspace-relative @angular/* imports resolve directly to the source. The tools/defaults.bzl file centralizes Bazel macro defaults used across the repo.

graph LR
  pnpm["pnpm install"] --> NodeModules["node_modules<br/>(pnpm content-addressable store)"]
  NodeModules --> Bazel["bazelisk build/test"]
  Bazel --> NgPackage["@angular/* dist/<br/>(packages/*/npm_package)"]
  Bazel --> Adev["adev:build<br/>angular.dev static site"]
  Bazel --> Devtools["devtools shell-browser<br/>(Chrome/Firefox extension)"]

CI runs in GitHub Actions (.github/workflows). Pull requests trigger pr.yml and the cross-cutting ci.yml, plus dedicated workflows for the documentation preview deploy (adev-preview-build.yml, adev-preview-deploy.yml), benchmarks (benchmark-compare.yml, perf.yml), and merge automation (merge-ready-status.yml, assistant-to-the-branch-manager.yml).

Public API surface

Each package's exported API is captured in goldens/public-api/ as .d.ts snapshots. Adding or changing a public export requires running pnpm public-api:update and including the diff in the PR. This catches accidental breaks without a separate code review pass.

Where to learn more

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Architecture – Angular wiki | Factory