Skip to content

perf: cut the cost of Jest's file indexing - #206

Merged
V3RON merged 6 commits into
mainfrom
perf/lighter-host-crawl
Oct 16, 2026
Merged

V3RON merged 6 commits into
mainfrom
perf/lighter-host-crawl

Conversation

@V3RON

@V3RON V3RON commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

What is this?

Harness's Jest preset now makes Jest's file indexing cheaper in three ways. Jest builds its file map in a single process instead of starting a pool of worker processes, it no longer walks build and cache output that can never contain tests, and it finds files itself instead of asking watchman.

Before this change, every cold run, and every run after a file changed, started availableParallelism() - 1 Jest worker processes (11 on a 12-core machine, 2 on a 3-vCPU CI runner) only to index files. Harness's runner is serial, so those workers never run tests. Jest also indexed Harness's own .harness cache and native build output. On apps/playground, 636 of the 736 indexed files were build or cache output, and without watchman Jest walked about 110,000 directory entries on every run.

How does it work?

The preset sets maxWorkers: 1, so Jest's haste map processes files in the main process. Test execution is unchanged because Harness's runner was already serial.

The preset also adds modulePathIgnorePatterns for .harness, ios/Pods, ios/build, android/build, android/.gradle, android/app/build and android/app/.cxx. Jest's crawler checks these patterns before descending into a directory, so it never reads those folders. Jest appends a project's own modulePathIgnorePatterns to the preset's.

Finally, the preset sets watchman: false for Jest. Asking watchman costs two CLI process spawns per run, and watchman still lists every file, including the build output, before Jest filters it. Once that output is skipped, Jest's own crawl is cheaper. Watch mode uses Jest's built-in file watcher instead. Metro is unchanged and still uses watchman. Projects can override maxWorkers and watchman in their own Jest config.

Why is this useful?

Measured on apps/playground, with the Harness runner stubbed so only Jest's own work is counted:

  • Single process: a cold run with watchman went from 1.19 s to 0.58 s of CPU time, and a run after one changed file from 1.00 s to 0.57 s.
  • Skipping build output, without watchman: CPU went from 1.93 s to 0.30 s cold (84% less), wall time from 1.05 s to 0.63 s, and peak memory from 291 MB to 118 MB. The crawl now makes 59 directory reads instead of 15,827.
  • Skipping build output, with watchman: no measurable change, because watchman still lists every file and Jest filters the results afterwards.
  • Not using watchman, with build output skipped: a warm run uses 0.30 s of CPU instead of 0.54 s with watchman, and a cold run takes 0.63 s of wall time instead of 1.31 s.

Fewer processes and less crawling matter most on small CI runners, which have the fewest cores to spare next to Metro and the simulator.

@vercel

vercel Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
react-native-harness Ready Ready Preview Oct 16, 2026 9:55am UTC

Request Review

@V3RON V3RON changed the title perf: build Jest's file map in-process and stop using watchman perf: build Jest's file map in a single process Oct 16, 2026
@V3RON V3RON changed the title perf: build Jest's file map in a single process perf: cut the cost of Jest's file indexing Oct 16, 2026
@V3RON
V3RON merged commit f2793d4 into main Oct 16, 2026
6 checks passed
@V3RON
V3RON deleted the perf/lighter-host-crawl branch October 16, 2026 11:27

This branch was successfully deployed

1 active deployment
Preview — 9f105601 Deployed Oct 16, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant