This episode covers optimizing Jest suite performance: speeding up execution with watch mode and caching, managing workers with --runInBand and --maxWorkers, reducing setup overhead, and optimizing large test suites.

A slow suite is a hidden cost: every minute a developer waits is a minute lost from productivity. Episode 15 covers performance optimization for Jest — speeding up execution with watch mode and caching, managing workers with --runInBand and --maxWorkers, reducing setup overhead, and optimizing already-large test suites.
The goal isn't speed for its own sake, but making the feedback loop as fast as possible: the faster the suite, the more often you run it, and the better the quality it produces.
Watch mode re-runs only the tests affected by file changes. This is far faster than running the entire suite every time:
npx jest --watchThe command npx jest --watch monitors file changes and re-executes related tests. Jest computes dependencies between files, so changing src/math.js automatically runs math.test.js without touching other files.
Jest caches file transformation results so it doesn't re-transform unchanged files:
Jest cache: 98% transformed modules reusedCaching runs automatically. If the transformation changes — for example a new preset — Jest detects it and rebuilds the cache. --no-cache exists for debugging odd cases, but don't use it routinely since it removes the speed benefit.
These two flags control how Jest uses resources:
--runInBand: runs tests serially in a single process. Good for machines with few cores, or for debugging order and flakiness.--maxWorkers=n: limits the number of parallel workers, useful in CI with limited resources.npx jest --maxWorkers=2npx jest --maxWorkers=2 limits execution to two parallel processes. On machines with limited RAM, lowering the worker count prevents out-of-memory — a trade-off between speed and stability.
For monorepos with a multi-project config, Jest can run in project mode, running all projects in a single invocation — avoiding the overhead of restarting the runner for each project. Full details are in episode 17.
There's no magic number for --maxWorkers. The rule is simple: don't exceed the number of CPU cores, and lower it if RAM starts running out. In local development, let Jest use its default; in CI, read the resource limits from the runner configuration and set the worker count slightly below them so there's room for other processes.
Heavy work in beforeEach re-runs for every test — if there are 100 tests, that heavy work happens 100 times. Move genuinely one-time setup to beforeAll:
beforeAll(async () => {
database = await inisialisasiDatabase();
});
beforeEach(() => {
database.resetData();
});The expensive inisialisasiDatabase() runs once in beforeAll, while the lightweight resetData() runs on every test. This separation significantly reduces total suite time.
Jest transforms every imported file. The more node_modules that get transformed, the slower it gets. Use transformIgnorePatterns to exclude packages that are already pure CommonJS, and make sure only files that need transformation go into collectCoverageFrom.
Jest can tell you which tests are the slowest:
npx jest --detectOpenHandlesThe --detectOpenHandles flag helps find resources that aren't closed — leaked database connections or servers make the suite slower with each test. Combine it with a verbose report to see the time distribution per file.
If some test files are far slower than others, workers that finish early sit idle. Rebalance by splitting a giant test file into smaller files, or moving heavy setup into the beforeAll mentioned earlier. Even distribution makes parallelism work at its best.
Episode 15 covered suite performance optimization: watch mode and caching for fast feedback, the --runInBand, --maxWorkers, and project mode flags to manage resources, reducing setup overhead by moving heavy work to beforeAll, and optimizing large suites.
Key takeaways:
--runInBand for serial; --maxWorkers to limit parallelism.beforeEach to beforeAll.--detectOpenHandles finds leaked resources.In the next episode, episode 16, we'll cover custom matchers & helpers — building custom matchers with expect.extend, writing reusable helpers, testing domain-specific logic, and sharing helpers across projects.