Plate 46
esbuild-register vs jiti: 343ms vs 540ms Cold
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.
Aditya Challa4 min read
I timed esbuild-register 3.6.0 and jiti 2.7.0 on the same 61-file TypeScript graph: a cold run (jiti disk cache wiped) took a median 343 ms with esbuild-register and 540 ms with jiti. After jiti warmed its cache under node_modules/.cache/jiti, the same entry finished in 185 ms, while esbuild-register stayed near 350 ms.
Short answer: use esbuild-register for one-shot CI scripts and cold containers where nothing is cached. Prefer jiti when the same config or tool entry loads repeatedly on a developer machine. No affiliate links in this post.
What I tested
- Machine: 8 vCPU Intel Xeon / 15 GB RAM Linux cloud box, Node 20.19.2, tested 5 Oct 2026 (about 23:54 to 00:00 IST). Shared box; each timed run spawned a fresh Node process.
- Fixture: /workspace/bench-esbuild-jiti/. One entry.ts importing 20 mid modules and 40 util modules (61 .ts files). CommonJS package so node -r esbuild-register works without ESM loader flags.
- Tools: esbuild-register 3.6.0 (esbuild 0.25.12) via node -r esbuild-register src/entry.ts; jiti 2.7.0 via node_modules/.bin/jiti src/entry.ts. Both printed the same result 970.
- Timing: process wall clock via performance.now() around the child. Seven interleaved cold runs per tool with node_modules/.cache/jiti removed before every jiti cold sample. Seven warm pairs afterward without wiping the jiti cache.
- Findings: cold medians esbuild-register 343 ms / jiti 540 ms (~1.57x). Warm medians jiti 185 ms / esbuild-register 350 ms (~1.9x the other way).
- One surprise: jiti's first warm numbers looked "faster than physics" until I found the persistent cache folder. Without wiping it, you are not measuring cold transpile.
- Not tested: ESM-only packages, TypeScript path aliases, tsx or ts-node, Bun, Windows/macOS, watch mode, or compiling to a dist folder with tsc.
Is esbuild-register faster on a cold start?
| Metric | esbuild-register 3.6.0 | jiti 2.7.0 |
|---|---|---|
| Cold wall median (7 runs, jiti cache wiped) | 343 ms | 540 ms |
| Warm wall median (7 runs) | 350 ms | 185 ms |
| Modules loaded | 61 | 61 |
| Printed result | 970 | 970 |
On a wiped cache, yes. esbuild-register was about 1.6x faster for this graph. That is the number that matters for a fresh CI job or a container that never keeps node_modules/.cache.
For another "run TypeScript without a build step" angle on this site, see the tsx vs ts-node post. For compiler/minify speed after you do ship a build, see SWC vs esbuild vs Babel.
Does jiti win once the cache is warm?
Yes on this fixture. After the first successful jiti run, median wall time dropped to 185 ms while esbuild-register stayed around 350 ms with no equivalent on-disk module cache in this setup. If your CLI or Nuxt-style config loader starts dozens of times a day on the same laptop, jiti's cache is the decision number.
Who should not lean on that cache: locked-down CI images that wipe the workspace every job, or teams that treat node_modules/.cache as disposable. In those cases the cold ranking returns.
Should you switch from esbuild-register to jiti?
| Situation | My pick |
|---|---|
| One-shot script in CI / ephemeral container | esbuild-register |
| Local tool that reloads the same TS config often | jiti |
| You already depend on jiti via Nuxt, c12, or similar | Stay on jiti |
| You only need a require hook and already ship esbuild | esbuild-register is enough |
| You want a dedicated TS runner (tsx) instead of a register hook | Compare tsx vs ts-node first |
Bottom line: 343 ms versus 540 ms cold is real, and so is 185 ms warm jiti. Pick based on whether your process keeps a cache. For ecosystem upgrade pressure around TypeScript itself, see TypeScript 7: Should You Upgrade?. Package installs around either hook are covered in pnpm vs npm vs Bun.
How this was made: I generated the 61-file fixture, installed esbuild-register and jiti on the ShopperCove test box, timed interleaved cold and warm runs while wiping jiti's cache for cold samples, and kept the JSON; the write-up was drafted with AI help and checked against that output.
Sources
- https://www.npmjs.com/package/esbuild-register
- https://github.com/egoist/esbuild-register
- https://www.npmjs.com/package/jiti
- https://github.com/unjs/jiti
- https://esbuild.github.io/
- https://nodejs.org/api/cli.html#-r---require-module
Related
- https://www.shoppercove.com/blog/tsx-vs-ts-node
- https://www.shoppercove.com/blog/swc-vs-esbuild-babel
- https://www.shoppercove.com/blog/typescript-7-should-you-upgrade
- https://www.shoppercove.com/blog/pnpm-vs-npm-vs-bun
- https://www.shoppercove.com/blog/vitest-5-should-you-upgrade-october-2026
- https://www.shoppercove.com/blog/jest-vs-vitest
- https://www.shoppercove.com/blog/rolldown-vs-rollup
- https://www.shoppercove.com/blog/vite-vs-parcel
Lab evidence
What I found running this
Hands-on on ShopperCove box 5 Oct 2026 ~23:54-00:00 IST (8 vCPU Intel Xeon / 15 GB shared Linux, Node 20.19.2). Fixture: /workspace/bench-esbuild-jiti/ — 61 .ts modules (entry + 20 mid + 40 util), CommonJS. Tools: esbuild-register 3.6.0 (esbuild 0.25.12) via node -r; jiti 2.7.0 via local bin. 7 interleaved cold runs with node_modules/.cache/jiti wiped before each jiti sample: medians 343 ms vs 540 ms. 7 warm pairs without wipe: jiti 185 ms vs esbuild-register 350 ms. Output identical (970). Raw: /workspace/bench-esbuild-jiti/res-esbuild-jiti2.json. Not tested: ESM-only packages, path aliases, tsx/ts-node, Bun, Windows/macOS, watch mode, tsc emit. No affiliate.
Related links
Plate 94
Should You Leave Prettier? 1.59s vs 0.51s
dprint 0.60.1 vs Prettier 3.9.9 on 180 files (120 JS + 40 JSON + 20 MD, 38925 B pristine): write medians 514 ms vs 1586 ms; check 455 ms vs 1313 ms. Output 44805 vs 45285 B. All 120 JS files differed on arrow-param parentheses under these defaults.
5 Oct 2026
Plate 69
oxlint vs ESLint: Should You Switch? 9.8s vs 0.09s
oxlint 1.87.0 vs ESLint 9.39.4 on react-hook-form (301 files): 0.09 s vs 9.81 s single-thread (6.02 s with --concurrency auto, 1.10 s warm --cache). @oxlint/migrate ported 42 of 84 rules natively, 80 with JS plugins. 315 vs 562 warnings; seeded test 11/15 native, 13/15 with JS plugins, ESLint 15/15.
5 Oct 2026
Plate 80
size-limit vs bundlesize: Should You Switch? 761ms vs 604ms
size-limit 11.2.0 (@size-limit/file) vs bundlesize 1.0.0-beta.2 on 3 prebuilt dist JS files: brotli median 761 ms vs gzip 604 ms; size-limit gzip mode 621 ms. App reported 57.69 kB brotli / 62.20 kB gzip / 60.74 kB bundlesize gzip.
5 Oct 2026