Turbo 2.11.7 vs Nx 23.2.1 on 7 packages / 336 JS files: cold median 1177 ms vs 3378 ms (~2.9x). Warm both 7/7 local cache hits (Turbo wall ~138 ms / tool ~16 ms; Nx wall ~668 ms with daemon / tool ~31 ms).
5 min read
On a 7-package npm workspaces monorepo (336 JavaScript source files), Turbo 2.11.7 took a cold median 1177 ms and Nx 23.2.1 took 3378 ms (~2.9x). Warm local cache was 7/7 hits for both: Turbo wall median 138 ms (tool Time ~16 ms FULL TURBO), Nx wall median 668 ms with the daemon on (tool Run duration ~31 ms).
Short answer: leave Nx for Turbo when you want a thin task runner and faster cold CI on a simple package-script graph. Keep Nx when you need generators, project graph plugins, and a full monorepo framework. No affiliate links in this post.
@bench/pkg-a … pkg-f) and 1 app (@bench/web), 336 .js files under src/. Each build script reads its src/, does a small CPU hash loop, and writes dist/index.js.turbo 2.11.7 (turbo run build) and nx 23.2.1 (nx run-many -t build --all). Turbo packageManager field set; Nx targetDefaults.build.cache with outputs {projectRoot}/dist/**.--force; Nx --skip-nx-cache), then five interleaved warm cache-hit runs. Warm Nx measured with NX_DAEMON=true after a daemon warmup. Wall-clock via perf_counter around the full CLI.@nx/* executors beyond nx:run-script, pnpm/yarn workspaces, Windows/macOS, a 100+ package graph.| Tool | Cold median (wall) | Cold runs (ms) | Warm cache | Warm wall median | Tool-reported warm |
|---|---|---|---|---|---|
| Turbo 2.11.7 | 1177 ms | 1133 / 1177 / 1196 / 1177 / 1299 | 7/7 | 138 ms | ~16 ms FULL TURBO |
| Nx 23.2.1 | 3378 ms | 3209 / 3135 / 3378 / 3440 / 3443 | 7/7 | 668 ms | ~31 ms Run duration |
On this fixture Turbo finished cold builds about 2.9x faster. Both restored from local cache on every warm run. If your CI is mostly cold or cache-miss work on npm-script tasks, Turbo's lower overhead showed up clearly here.
Monorepo task runners sit next to bundler and package-manager choices. The Rspack vs Webpack post and the Rolldown vs Rollup post cover compile/bundle speed; the pnpm vs npm vs Bun post covers install speed. This post is only the task-orchestrator decision. For a Turbo point-release note on this site, see Turborepo 2.11.7.
Nx is a monorepo platform, not only a cache wrapper. You lose first-party generators, inferred project graph plugins, module-boundary rules, and Nx Cloud workflows if you drop it for Turbo alone. Teams already deep in @nx/react or @nx/next executors should not treat this 7-package npm-script bench as a migration green light.
Also expect different config shapes. Turbo stayed close to package.json scripts plus turbo.json tasks. Nx needed explicit outputs under targetDefaults before local cache hit 7/7 on this fixture.
| Situation | My pick |
|---|---|
| Thin npm/pnpm workspaces, scripts already define build/lint/test | Prefer Turbo; re-measure your graph |
| You need generators, boundaries, or Nx plugins | Stay on Nx |
| CI is mostly cold or cache-bust builds on small packages | Turbo's cold ~2.9x here is the signal to test |
| You already pay for Nx Cloud remote cache and it is warm | Stay; this lab did not test remote cache |
| First PR would rewrite every project.json / executor | Stay on Nx unless the team wants a thin runner |
Bottom line: on 7 packages and 336 JS files, Turbo cold median was 1177 ms and Nx was 3378 ms, with both hitting full local cache when warm. Who should not switch yet: teams that depend on Nx generators and plugins. Everyone else comparing task runners should run the same cold/warm pair on their own workspace.
How this was made: I built the workspaces fixture, ran interleaved Turbo and Nx builds on the ShopperCove test box, and kept the timing JSON; the write-up was drafted with AI help and checked against that output.
Lab evidence
Hands-on on ShopperCove box 5 Oct 2026 ~23:35-23:45 IST (8 vCPU Intel Xeon / 15 GB shared Linux, Node 20.19.2). Fixture: npm workspaces, 7 projects (6 libs + 1 app), 336 JS src files; build scripts CPU-hash src → dist. Versions: turbo 2.11.7, nx 23.2.1. Cold: 5 interleaved (turbo --force; nx --skip-nx-cache). Cold medians: turbo 1177.19 ms (1133.12/1176.741/1195.795/1177.19/1299.236); nx 3377.905 ms (3209.046/3135.461/3377.905/3440.206/3442.991). Warm: 7/7 cache hits both; turbo wall median 137.716 ms (daemon N/A; tool Time ~16 ms); nx wall median 668.264 ms with NX_DAEMON=true (tool Run duration ~31 ms). Raw: /workspace/bench-turbo-nx/res-turbo-nx.json. Not tested: remote cache, Nx generators/plugins beyond nx:run-script, pnpm/yarn, Windows/macOS, 100+ package graphs. No affiliate.
Playwright 1.55.1 Chromium vs Cypress 14.5.4 Electron on one local smoke (visit /, assert h1, click, assert). Warm medians (7 rounds after 1 warm-up): Playwright 1,466 ms vs Cypress 4,243 ms (~2.9x). Disk: PW node_modules ~12 MB + cache ~918 MB; Cypress node_modules ~23 MB + cache ~601 MB. Fixture /workspace/bench-pw-cy/.
Hands-on6 Oct 20264 min read
Turbo 2.11.7 vs Lage 2.17.0 on a 4-package diamond npm workspace (250k-iter build scripts): cold wall medians 1,974 ms vs 3,007 ms (~1.5x); Turbo warm 4/4 cache hits ~0.50 s; Lage warm ~1.49 s. Lage required git init.
Hands-on5 Oct 20264 min read
esbuild-register 3.6.0 vs jiti 2.7.0 on a 61-file TypeScript graph: cold wall medians 343 ms vs 540 ms (~1.57x); after jiti disk cache warm, 185 ms vs esbuild-register 350 ms. Same printed result 970.
Hands-on5 Oct 20264 min read