## Current Behavior `nx.json` `targetDefaults` accepts the new filtered **array shape** (entries matched by `target`/`executor` and narrowed by `projects`/`plugin`), alongside the legacy record shape. This was introduced and refined across: - #35340 — feat: support filtered array-shape targetDefaults with projects and source - #35711 — fix: do not drop target defaults in the 23.0.0 array migration - #35752 — docs: document the `convert-target-defaults-to-array` migration - #35991 — docs: rewrite the targetDefaults reference and guide for the array shape ## Expected Behavior This PR **reverts the array-shape `targetDefaults` feature pending a redesign**, with the intent that it be **reapplied** once the design is finalized. `targetDefaults` returns to the record-shape-only form (`Record<string, Partial<TargetConfiguration>>`). To keep reapplication easy, the revert is split into focused commits that mirror the original PRs — the feature can be brought back later by reverting these reverts. Changes: - Restore the `TargetDefaults` type; remove `TargetDefaultEntry`, `TargetDefaultsRecord`, and `NormalizedTargetDefaults` - Restore the core target-defaults matcher and project-configuration utils to the record-shape logic - Remove the `convert-target-defaults-to-array` migration (and its registration/docs) - Remove the devkit `upsertTargetDefault`/`findTargetDefault` helpers and the `normalize-target-defaults` utility; restore generators across all plugins (angular, cypress, react, jest, eslint, vite, etc.) to write the record shape - Restore the `nx.json` schema `targetDefaults` definition and revert the array-shape documentation Unrelated changes that landed in the same files after the feature are **preserved** (the `CreateNodesV2`→`CreateNodes` rename, the `findMatchingConfigFiles` optimization, the `nx migrate` config, `.gitignore` entries, migration-doc packaging globs, and the maven `createNodesV2` migration). ## Related Issue(s) Reverts #35340, #35711, #35752, #35991 (to be reapplied after redesign). --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
Nx CLI Benchmarks
Synthetic workspace with 1110 projects arranged in a 3-level fan-out (10 groups x 10 subs x 10 leaves). Each project defines build, copy, and cat targets that operate on a shared lorem.md file — no real compilation, just enough I/O to exercise Nx's task pipeline.
Workspace Targets
| Target | Command | Cached | Outputs | Dependencies |
|---|---|---|---|---|
| build | cp lorem.md → dist/output.md |
Yes | Yes | ^build |
| copy | cp lorem.md → copy-out/output.md |
Yes | Yes | None |
| cat | cat lorem.md |
Yes | No | None |
Quick Start
Prerequisites: hyperfine (cargo install hyperfine)
# Run all benchmarks and compare against goals + baseline
pnpm nx run benchmarks
# Run a single benchmark
pnpm nx bench:version benchmarks
pnpm nx bench:show-projects benchmarks
pnpm nx bench:cat-warm benchmarks
pnpm nx bench:copy-warm benchmarks
Each bench:* target depends on ^build so the Nx packages are compiled first.
Benchmarks
| Benchmark | What it runs | What it measures |
|---|---|---|
version |
nx --version |
CLI startup and module loading |
show-projects |
nx show projects |
Project graph construction via daemon |
cat-warm |
run-many -t cat x1110 |
Task scheduling + hashing with no output artifacts |
copy-warm |
run-many -t copy x1110 |
Cached task execution with output tracking |
build-warm |
run-many -t build x1110 |
Cached tasks with topological deps (currently disabled) |
All benchmarks use NX_NO_CLOUD=true, run nx reset before each iteration, and collect at least 5 runs (10 for version) via hyperfine.
Goals and Baselines
Performance is tracked with two files:
goals.json(committed) — target times the team agrees on. CI fails if a benchmark exceeds its goal.baseline.json(gitignored) — your local machine's numbers for personal comparison.
The run-benchmarks.ts script reads both and prints a table with colored deltas showing how the current run compares to each.
Setting the Baseline
# First run auto-creates baseline.json
pnpm nx run benchmarks
# Explicitly overwrite with fresh numbers
pnpm nx run benchmarks -- --set-baseline
How It Works
- Each
bench:*script invokes hyperfine and writes aresults-<name>.jsonfile. - The
runtarget depends on allbench:*targets, so they execute in sequence (parallelism: false). - After all benchmarks finish,
run-benchmarks.tsreads the result files and prints the comparison table.
CI
Benchmarks run as part of the affected target pipeline in CI (nx affected --targets=...bench). The goals in goals.json act as the regression gate.