Performance benchmark of the Angular framework across versions v14–v22: nine idiomatic variants of the same test application plus a fully automated measurement harness (build time, bundle size, Lighthouse, runtime performance).
Companion materials for the master's thesis "The Evolution of the Angular Framework and Its Impact on Application Performance" (original title: „Ewolucja frameworka Angular i jej wpływ na wydajność aplikacji") — Jakub Januszewski, Faculty of Computing and Telecommunications, Poznan University of Technology, 2026.
├── v14/ … v22/ nine variants of the test application (one per framework version)
└── benchmark/ measurement harness (Node.js)
├── bench.mjs measurements: build, bundle, Lighthouse, runtime FPS/INP
├── gen-latex.mjs LaTeX table/figure generator from the results
└── results/ raw results (JSON/CSV) and generated .tex files
Every variant implements identical business logic: an analytics dashboard with
5000 cards, a simulated data stream replacing the entire collection every
100 ms (forcing a full change detection cycle), and a hero banner with a 7 MB
image (LCP/CLS testing). Each variant is written idiomatically for its framework
version, using the default ng new configuration:
| Version | Characteristics |
|---|---|
| v14 | NgModule, *ngFor/*ngIf with trackBy, Zone.js |
| v15 | Standalone API (stable), NgOptimizedImage with priority |
| v16 | + signals (developer preview) — state as signal() |
| v17 | + built-in control flow (@if/@for track), stable signals, esbuild/Vite |
| v18 | + input()/output() instead of decorators |
| v19 | standalone as the default behaviour |
| v20 | new CLI naming convention; still Zone.js |
| v21–v22 | zoneless mode as the default configuration |
The data stream does not start automatically — it is activated by a button only during the runtime test, so it does not distort the page-load measurements (Lighthouse).
- Node.js 24.x (a single runtime for all framework versions),
- Google Chrome (Lighthouse and the runtime test use the system installation),
- Windows / macOS / Linux (the thesis measurements were taken on Windows 11).
cd v21
npm install
npx ng serve # http://localhost:4200cd benchmark
npm install
# full run: 9 versions × (3 cold builds + 5×Lighthouse + 5×runtime)
node bench.mjs --runtime-runs 5
# CLS experiment: image response delayed by 2 s (results stored separately)
node bench.mjs --skip build,fps --image-delay 2000
# LaTeX tables and figures from the collected results
node gen-latex.mjsKey bench.mjs options:
| Option | Default | Description |
|---|---|---|
--versions 14,15,… |
all | which versions to measure |
--build-runs N |
3 | number of cold builds (dist and .angular/cache wiped) |
--lh-runs N |
5 | number of Lighthouse runs |
--runtime-runs N |
1 | number of FPS/INP test runs |
--fps-seconds N |
10 | FPS measurement duration |
--preset desktop|mobile |
desktop | Lighthouse emulation |
--image-delay MS |
0 | delayed image responses (CLS experiment) |
--skip build,lighthouse,fps |
— | skip stages; results are merged with existing ones |
Medians are reported; raw values of every run are stored in
benchmark/results/v*.json, aggregated into results.json and results.csv.
Note: the runtime test opens a visible Chrome window (FPS measurement requires real frame rendering) — keep the machine idle during measurements.
| Metric | v14 | v22 | Change |
|---|---|---|---|
| Cold build time (median) | 15.2 s | 5.7 s | −63% (step change at v17: esbuild/Vite) |
| Bundle size (gzip) | 78.0 kB | 71.5 kB | −14% vs v20 (zoneless drops Zone.js) |
| Total Blocking Time | 138 ms | 93 ms | −33% |
| FPS under load | 9.6 | 10.7 (v21: 11.6) | +21% (v21 vs v20) |
| CLS with a delayed image | 0.261 | 0.000 | NgOptimizedImage (v15) eliminates layout shifts |