This guide is for engineers who integrate Jest deeply, operate it in CI at scale, extend it with custom runners/environments/reporters, or contribute to Jest itself. It documents Jest's monorepo architecture, the end-to-end test-run pipeline, the complete configuration reference (every option with its default and scope), the extension points, and operational concerns like performance tuning, caching, and CI integration.
For day-to-day test authoring — writing tests, matchers, mocking, snapshots — see the User Guide. This guide assumes that material and goes beneath it.
Note
Jest is distributed as a single installable package (
jest) but built as a monorepo of ~45 cooperating packages underpackages/. Understanding which package owns which responsibility is the key to operating and extending Jest effectively.
1. Executive Summary
Jest is a batteries-included JavaScript/TypeScript testing framework. Architecturally it is a pipeline of specialized packages orchestrated by jest-core:
- The CLI (
jest-cli) parses arguments and hands off tojest-core. jest-configresolves and normalizes configuration into a frozen global config plus one project config per project.jest-corebuilds aSearchSourceover ajest-haste-mapfile index to find test files, orders them with a test sequencer, then dispatches them.- A runner (
jest-runnerby default) executes each test file — in-process or across ajest-workerpool. - For each file, a
jest-runtimesandbox provides module loading, mocking, and the test environment (jest-environment-nodeorjest-environment-jsdom). - The test framework (
jest-circusby default) runs thedescribe/testblocks; assertions go throughexpect. - Results flow back through
jest-test-resultto the reporters (jest-reporters).
| Property | Value |
|---|---|
| Language | TypeScript (compiled to CommonJS + type declarations) |
| Distribution | npm package jest (meta-package over jest-cli) |
| Default test framework | jest-circus |
| Default environment | jest-environment-node |
| Default sequencer | @jest/test-sequencer |
| Parallelism | jest-worker pool of child processes (or worker threads) |
| Node.js support | ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 |
| License | MIT (Meta Platforms, Inc.) |
| Repo layout | Yarn-workspaces monorepo, packages/* |
2. Architecture
2.1 The test-run pipeline
$ jest --coverage src/
│
▼
┌──────────────────────────────┐
│ jest-cli │ parse argv (args.ts), validate, build Config.Argv
│ run() → @jest/core runCLI() │
└──────────────┬───────────────┘
▼
┌──────────────────────────────┐
│ jest-config │ resolve config file, apply preset, normalize,
│ readConfigs() │ split into GlobalConfig + ProjectConfig[]
└──────────────┬───────────────┘
▼
┌──────────────────────────────┐
│ jest-core │ orchestration: createContext per project
│ runJest() / watch() │
│ ├─ jest-haste-map ─────────┼─► crawl + index files (watchman or node fs)
│ ├─ SearchSource ─────────┼─► select test files (testMatch / changed / patterns)
│ ├─ @jest/test-sequencer ────┼─► order tests (failed-first, slowest-first)
│ └─ TestScheduler ─────────┼─► dispatch to runner(s)
└──────────────┬───────────────┘
▼
┌──────────────────────────────┐
│ jest-runner │ per-file execution; spawns jest-worker pool
│ (one worker per CPU slot) │ sets JEST_WORKER_ID per worker
└──────────────┬───────────────┘
▼ (inside each worker, per test file)
┌──────────────────────────────┐
│ jest-runtime │ sandboxed module registry: require/import,
│ + jest-environment-node/jsdom│ jest.mock, transform via jest-transform,
│ + jest-resolve │ resolve via jest-resolve
└──────────────┬───────────────┘
▼
┌──────────────────────────────┐
│ jest-circus (test framework) │ run describe/test/hooks; assertions via `expect`
│ + expect + jest-snapshot │ pretty-format + jest-diff for output
└──────────────┬───────────────┘
▼
┌──────────────────────────────┐
│ jest-test-result → jest-reporters │ aggregate + render (default, summary,
│ │ coverage, GitHub Actions, JSON, custom)
└────────────────────────────────────┘
2.2 Package inventory
The monorepo ships these packages (selected high-priority ones). All are published under the @jest/ scope or as jest-*.
| Package | Responsibility |
|---|---|
jest |
Meta-package; the installable entry point |
jest-cli |
Argument parsing (args.ts), the jest binary, runCLI bootstrap |
@jest/core (jest-core) |
Orchestration: runCLI, runJest, watch mode, SearchSource, TestScheduler |
jest-config |
Config resolution, normalization, defaults, deprecations, presets |
jest-runner |
Default test runner; manages the worker pool and per-file execution |
jest-runtime |
Sandboxed module system, mocking integration, ESM/CJS loaders |
jest-circus |
Default test framework (the describe/test/hooks engine) |
jest-jasmine2 |
Legacy test framework (opt-in via testRunner: 'jest-jasmine2') |
expect |
Assertion library and matcher implementations |
expect-utils |
Shared equality logic used by expect |
jest-snapshot |
Snapshot serialization, storage, and matching |
jest-snapshot-utils |
Snapshot file parsing helpers |
jest-mock |
Mock functions, spies, automatic module mocks |
jest-each |
test.each / describe.each table-driven tests |
jest-environment-node |
Default Node.js test environment |
jest-environment-jsdom |
DOM environment (separate install since v28) |
jest-environment-jsdom-abstract |
Shared base for jsdom environments |
jest-environment |
Environment interface/types |
jest-haste-map |
File crawler and module map (Facebook "Haste" system) |
jest-resolve |
Module resolution (node, exports/imports maps, conditions) |
jest-resolve-dependencies |
Dependency graph for --findRelatedTests |
jest-transform |
Transformer pipeline + transform cache |
babel-jest |
Default Babel-based transformer |
babel-plugin-jest-hoist |
Hoists jest.mock calls above imports |
babel-preset-jest |
Babel preset bundling the hoist plugin |
jest-reporters |
Built-in reporters (default, summary, coverage, GitHub Actions, etc.) |
jest-watcher |
Watch-mode interactive UI and plugin interface |
jest-worker |
Generic worker-pool abstraction (child processes / threads) |
jest-test-result |
Result data structures and aggregation |
jest-test-sequencer |
Default test ordering strategy |
jest-message-util |
Stack-trace formatting and error messages |
jest-console |
Per-test console capture and buffering |
jest-changed-files |
Git/hg integration for --onlyChanged |
jest-validate |
Config/CLI option validation with "did you mean" hints |
jest-diff |
Structural diff rendering for assertion failures |
pretty-format |
Serialization engine for snapshots and diffs |
diff-sequences |
Longest-common-subsequence diff algorithm |
jest-get-type |
Runtime type detection used across packages |
jest-leak-detector |
Memory-leak detection for --detectLeaks |
jest-fake-timers |
Modern and legacy fake-timer implementations |
jest-source-map |
Source-map handling for stack traces |
jest-docblock |
Parses @jest-environment and other docblock pragmas |
jest-regex-util |
Cross-platform regex/path helpers |
jest-pattern |
Test path pattern matching (TestPathPatterns) |
jest-util |
Shared utilities (isInteractive, clearLine, etc.) |
jest-types |
Shared TypeScript types (Config, Global, etc.) |
jest-schemas |
JSON schemas for config validation |
create-jest |
The npm init jest scaffolding tool |
jest-create-cache-key-function |
Helper for transformers to build cache keys |
Tip
When debugging unexpected behavior, identify which package owns the concern. A resolution failure belongs to
jest-resolve; a transform problem tojest-transform/babel-jest; a snapshot mismatch tojest-snapshot; a parallelism issue tojest-runner/jest-worker.
2.3 Global config vs. project config
jest-config splits the normalized options into two frozen objects:
- GlobalConfig — settings that apply to the whole run:
bail,coverageReporters,maxWorkers,watch,reporters,testPathPatterns,testNamePattern,verbose,silent,forceExit,shard,seed, etc. These are global-only and cannot be set inside an individual project. - ProjectConfig — settings that apply per project:
testEnvironment,transform,moduleNameMapper,setupFiles,setupFilesAfterEnv,roots,testMatch,snapshotSerializers,automock,clearMocks,coveragePathIgnorePatterns, etc.
This split is why multi-project setups (the projects option) let each project define its own environment and transforms while the global flags (workers, reporters, watch) are shared.
Important
If you put a global-only option (e.g.
coverageReporters,maxWorkers) inside an entry ofprojects, Jest emits: "Option … is not supported in an individual project configuration. Move it to the root configuration." Global options belong at the top level.
2.4 The Haste module map and caching
jest-haste-map crawls your files once per run and builds an in-memory map of modules, mocks, and (for React Native) platform-specific files. It can crawl with Watchman (fast, incremental) when available, falling back to a Node.js filesystem crawl.
The transform cache and haste map live under the cache directory, which defaults to your OS temp dir under jest/ (suffixed per-UID on POSIX). Override with cacheDirectory. Clear it with jest --clearCache.
<os-tmp>/jest_<uid>/ ← default cache directory
haste-map-* ← serialized module map
jest-transform-cache-* ← transformed source cache, keyed by content + config
Note
The transform cache key incorporates the transformer, its config, and the file content. Changing your Babel/transform config invalidates the cache automatically. The haste map respects
modulePathIgnorePatternsand (in watch mode)watchPathIgnorePatterns.
3. System Requirements
| Item | Requirement |
|---|---|
| Node.js | ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0 |
| Watchman (optional) | Recommended for large repos in watch mode; set watchman: false to disable |
| Babel (optional) | Required if using babel-jest (the default transform for JS/TS) |
| jsdom (optional) | jest-environment-jsdom, only if testing DOM code |
| Prettier (optional) | Required for inline snapshots; path set by prettierPath |
Warning
Odd-numbered Node releases (19, 21, 23) are intentionally excluded from the supported
enginesrange. CI images must use 18.14+, 20, 22, or 24+.
4. Complete Configuration Reference
Every option below is a real Jest configuration key. Default is the value Jest ships (from jest-config's Defaults.ts); blank means there is no default (the feature is off / unset unless you set it). Scope indicates whether the option is global (whole run) or project-level.
4.1 Core / discovery
| Option | Default | Scope | Description |
|---|---|---|---|
rootDir |
dir of config file | project | Root directory Jest scans for tests and modules |
roots |
["<rootDir>"] |
project | Directories to search for files |
testMatch |
["**/__tests__/**/*.?([mc])[jt]s?(x)", "**/?(*.)+(spec|test).?([mc])[jt]s?(x)"] |
project | Globs to detect test files |
testRegex |
[] |
project | Regex alternative to testMatch (mutually exclusive) |
testPathIgnorePatterns |
["/node_modules/"] |
project | Regexes; matching test paths are skipped |
moduleFileExtensions |
["js","mjs","cjs","jsx","ts","mts","cts","tsx","json","node"] |
project | Extensions tried when resolving extensionless imports |
moduleDirectories |
["node_modules"] |
project | Directory names searched recursively upward |
modulePaths |
— | project | Absolute paths added to the resolution search (alternative to NODE_PATH) |
modulePathIgnorePatterns |
[] |
project | Regexes; matching modules are hidden from the loader |
moduleNameMapper |
{} |
project | Map import patterns → modules/stubs |
roots / <rootDir> token |
— | project | <rootDir> expands to the project root in path options |
4.2 Environment & execution
| Option | Default | Scope | Description |
|---|---|---|---|
testEnvironment |
"jest-environment-node" |
project | Environment for tests (node, jsdom, or a path) |
testEnvironmentOptions |
{} |
project | Options passed to the environment (e.g. jsdom url) |
testRunner |
"jest-circus/runner" |
project | Test framework runner |
runner |
"jest-runner" |
project | Top-level runner managing the worker pool |
testSequencer |
"@jest/test-sequencer" |
global | Strategy for ordering test files |
maxWorkers |
"50%" |
global | Worker pool size (number or % of CPUs) |
maxConcurrency |
5 |
global | Max simultaneous test.concurrent tests |
workerThreads |
false |
global | Use worker threads instead of child processes |
workerIdleMemoryLimit |
— | global | Recycle a worker that exceeds this memory (number or %) |
workerGracefulExitTimeout |
500 |
global | ms to wait for a worker to exit before force-kill |
testTimeout |
5000 |
project | Per-test timeout in ms |
bail |
0 |
global | Stop after n failing suites (true = 1) |
injectGlobals |
true |
project | Inject describe/test/expect as globals |
globals |
{} |
project | Variables available in all test environments |
sandboxInjectedGlobals |
— | project | Globals to inject into the test sandbox (was extraGlobals) |
4.3 Setup & teardown
| Option | Default | Scope | Description |
|---|---|---|---|
setupFiles |
[] |
project | Modules run once before the framework is installed |
setupFilesAfterEnv |
[] |
project | Modules run before each test file (framework ready) |
globalSetup |
— | project | Async module run once before all suites |
globalTeardown |
— | project | Async module run once after all suites |
4.4 Mocking & modules
| Option | Default | Scope | Description |
|---|---|---|---|
automock |
false |
project | Auto-mock all imported modules |
clearMocks |
false |
project | jest.clearAllMocks() before each test |
resetMocks |
false |
project | jest.resetAllMocks() before each test |
restoreMocks |
false |
project | jest.restoreAllMocks() before each test |
resetModules |
false |
project | Reset the module registry before each test |
unmockedModulePathPatterns |
— | project | Regexes for modules never auto-mocked |
resolver |
— | project | Path to a custom resolver |
dependencyExtractor |
— | project | Path to a custom dependency extractor |
4.5 Transformation
| Option | Default | Scope | Description |
|---|---|---|---|
transform |
{ "\\.[jt]sx?$": "babel-jest" } (when Babel present) |
project | Map file patterns → transformers |
transformIgnorePatterns |
["/node_modules/", "\\.pnp\\.[^\\/]+$"] |
project | Source paths skipped by transformation |
extensionsToTreatAsEsm |
[] |
project | Extensions loaded as native ES modules |
haste |
{computeSha1:false, enableSymlinks:false, forceNodeFilesystemAPI:true, throwOnModuleCollision:false} |
project | Haste module-system settings |
watchman |
true |
project | Use Watchman for file crawling |
4.6 Coverage
| Option | Default | Scope | Description |
|---|---|---|---|
collectCoverage |
false |
both | Collect coverage during the run |
collectCoverageFrom |
— | project | Globs of files to include in coverage |
coverageDirectory |
— | both | Output directory for coverage reports |
coverageProvider |
"babel" |
global | Instrumentation engine: babel or v8 |
coverageReporters |
["json","text","lcov","clover"] |
global | Istanbul reporters to emit |
coveragePathIgnorePatterns |
["/node_modules/"] |
project | Paths excluded from coverage |
coverageThreshold |
— | global | Minimum coverage; run fails if unmet |
forceCoverageMatch |
[] |
project | Globs to force-include files normally ignored |
4.7 Reporting & output
| Option | Default | Scope | Description |
|---|---|---|---|
reporters |
["default"] |
global | Reporter list (built-in names, paths, or [path, options]) |
verbose |
false |
both | Report each individual test |
silent |
false |
both | Suppress test console output |
noStackTrace |
false |
global | Omit stack traces from output |
errorOnDeprecated |
false |
project | Throw helpful errors when deprecated APIs are used |
slowTestThreshold |
5 |
project | Seconds before a test is flagged as slow |
notify |
false |
global | Desktop notifications for results |
notifyMode |
"failure-change" |
global | When to notify |
snapshotFormat |
{escapeString:false, printBasicPrototype:false} |
both | pretty-format options for snapshots |
snapshotResolver |
— | project | Custom mapping of test file → snapshot file |
snapshotSerializers |
[] |
project | Custom serializers for snapshot output |
testLocationInResults |
false |
project | Add location to result objects |
json |
false |
global | Emit results as JSON |
outputFile |
— | global | File to write JSON results to |
testResultsProcessor |
— | global | Custom results post-processor module |
4.8 Watch & change detection
| Option | Default | Scope | Description |
|---|---|---|---|
watch |
false |
global | Watch related files |
watchAll |
false |
global | Watch all files |
watchPathIgnorePatterns |
[] |
project | Paths that do not trigger a re-run |
watchPlugins |
— | global | Custom watch-mode plugins |
changedSince |
— | global | Run tests changed since a branch |
changedFilesWithAncestor |
false |
global | Include the last commit's changes |
4.9 Misc runtime flags
| Option | Default | Scope | Description |
|---|---|---|---|
cache |
true |
project | Use the transform cache |
cacheDirectory |
OS temp /jest_<uid> |
project | Cache location |
ci |
auto-detected (ci-info) |
global | CI mode (no new snapshot writes) |
detectLeaks |
false |
both | Experimental leak detection |
detectOpenHandles |
false |
both | Report handles preventing exit |
openHandlesTimeout |
1000 |
global | ms before warning about open handles (0 disables) |
forceExit |
— | global | Force process exit after the run |
logHeapUsage |
— | global | Log heap usage after each test |
passWithNoTests |
false |
global | Don't fail when zero tests match |
randomize |
— | global | Shuffle test order within files |
seed |
random | global | Randomization seed |
showSeed |
— | global | Print the seed in the summary |
runTestsByPath |
false |
global | Treat patterns as exact paths |
testFailureExitCode |
1 |
global | Exit code on test failure |
fakeTimers |
{enableGlobally:false} |
project | Default fake-timer configuration |
prettierPath |
"prettier" |
project | Module used to format inline snapshots |
waitForUnhandledRejections |
false |
both | Give the event loop a turn to handle late rejections |
displayName |
— | project | Label for the project in multi-project output |
preset |
— | project | Base config to extend |
projects |
— | global | Run multiple project configs in one invocation |
id |
— | project | Stable project identifier |
4.10 Deprecated options
These options are still parsed but emit a deprecation warning (and throw under errorOnDeprecated). Migrate to the replacement.
| Deprecated | Replacement |
|---|---|
browser |
Install browser-resolve and use the resolver option |
collectCoverageOnlyFrom |
collectCoverageFrom |
extraGlobals |
sandboxInjectedGlobals |
init (the --init flag) |
The create-jest package (npm init jest) |
moduleLoader |
runtime |
preprocessorIgnorePatterns |
transformIgnorePatterns |
scriptPreprocessor |
transform |
setupTestFrameworkScriptFile |
setupFilesAfterEnv |
testPathDirs |
roots |
testPathPattern (config) |
--testPathPatterns (CLI-only) |
testURL |
testEnvironmentOptions.url |
timers |
fakeTimers |
5. Extension Points
Jest is designed to be extended at every stage of the pipeline. Each extension is a module path you reference in configuration.
5.1 Custom transformer
A transformer converts source files Jest cannot run natively. It implements process (and optionally processAsync) plus a getCacheKey:
// my-transformer.js
module.exports = {
process(sourceText, sourcePath, options) {
return {code: compile(sourceText)};
},
getCacheKey(sourceText, sourcePath, options) {
return createHash(sourceText + options.configString);
},
};
// jest.config.js
module.exports = {
transform: {'\\.custom$': '<rootDir>/my-transformer.js'},
};
Transformers can take options via the array form: transform: {'\\.js$': ['babel-jest', {presets: [...]}]}. Use jest-create-cache-key-function to build robust cache keys.
5.2 Custom test environment
An environment provides the global sandbox (global, timers, the module context). Extend the abstract base:
const NodeEnvironment = require('jest-environment-node').default;
class CustomEnvironment extends NodeEnvironment {
async setup() {
await super.setup();
this.global.MY_GLOBAL = await connect();
}
async teardown() {
await this.global.MY_GLOBAL.close();
await super.teardown();
}
handleTestEvent(event, state) { /* circus events */ }
}
module.exports = CustomEnvironment;
Select it with testEnvironment: '<rootDir>/CustomEnvironment.js' or a per-file docblock.
Note
Environment
teardown()throwing surfaces as a test-environment error (e.g. "teardown error from custom environment"). Alwaysawait super.teardown()last.
5.3 Custom runner
runner swaps the top-level execution strategy (useful for non-test workloads like linting through Jest). The default is jest-runner. A custom runner exposes a class with a runTests method and may declare itself serial or parallel.
5.4 Custom reporter
Reporters receive lifecycle callbacks and render results:
class MyReporter {
onRunStart(results, options) {}
onTestStart(test) {}
onTestResult(test, testResult, aggregatedResult) {}
onRunComplete(contexts, results) {}
}
module.exports = MyReporter;
// jest.config.js
module.exports = {
reporters: ['default', ['<rootDir>/MyReporter.js', {verbose: true}]],
};
Built-in reporters include default, the summary reporter, the coverage reporter, the JSON reporter, and a GitHub Actions reporter that emits annotations in CI.
Important
A reporter entry must be a string or a
[path, options]tuple. Anything else throws "Reporter at index N must be of type: array or string".
5.5 Custom resolver
resolver replaces module resolution — needed for unusual package layouts, custom conditions, or PnP. It receives a request and options and returns an absolute path.
5.6 Custom test sequencer
testSequencer controls file ordering. The default @jest/test-sequencer runs previously-failed and slowest tests first to surface failures quickly and balance the worker pool. Extend @jest/test-sequencer and override sort/shard.
5.7 Watch plugins
watchPlugins add interactive watch-mode commands (e.g. jest-watch-typeahead). Each plugin can register a key, a prompt, and hooks into the watch run.
6. Multi-Project Configuration
A single Jest invocation can run several configurations using projects. Each entry is a path or an inline config; each gets its own environment, transforms, and roots, while global options (workers, reporters, watch) are shared.
// jest.config.js
module.exports = {
projects: [
{
displayName: 'node',
testEnvironment: 'node',
testMatch: ['<rootDir>/packages/**/*.test.ts'],
},
{
displayName: 'dom',
testEnvironment: 'jsdom',
testMatch: ['<rootDir>/ui/**/*.test.tsx'],
},
],
};
Run or skip individual projects from the CLI:
jest --selectProjects node
jest --ignoreProjects dom
Warning
Two projects must not resolve to the same config path. Jest aborts with "Whoops! Two projects resolved to the same config path" — usually caused by a
projectsglob that includes a directory with no Jest config.
7. CI Integration
7.1 CI mode
Jest auto-detects CI via the ci-info package and most CI providers set CI=true. In CI mode, Jest refuses to write new snapshots so a missing/obsolete snapshot fails the build rather than silently passing. Force it with --ci.
jest --ci --coverage --reporters=default --reporters=jest-junit
7.2 Sharding across machines
For large suites, split the run across parallel CI jobs with --shard:
# job 1 of 4
jest --shard=1/4
# job 2 of 4
jest --shard=2/4
Each shard runs a deterministic, disjoint subset. Combine coverage afterward with a merge step (e.g. nyc merge / istanbul).
7.3 Recommended CI invocation
jest --ci \
--runInBand=false \
--maxWorkers=2 \
--coverage \
--coverageReporters=lcov --coverageReporters=text-summary \
--reporters=default --reporters=github-actions
Tip
On constrained CI runners, an explicit
--maxWorkers=2(or a low percentage) often beats the default50%because CI containers frequently misreport CPU count. Measure both.
Caution
The
JEST_WORKER_IDenvironment variable is set by Jest inside each worker (starting at1). Use it to give each worker an isolated resource (e.g. a database schematest_db_${JEST_WORKER_ID}) and avoid cross-worker collisions.
8. Performance Tuning
| Lever | Effect | When to use |
|---|---|---|
maxWorkers |
Pool size | Lower in CI containers; "50%" default suits dev machines |
workerThreads: true |
Threads vs. processes | Can reduce startup overhead; test stability first |
--runInBand |
Single process | Debugging, or very small suites where worker startup dominates |
cache (default on) |
Reuse transforms | Never disable in CI without reason; warm the cache |
coverageProvider: 'v8' |
Native coverage | Faster than Babel instrumentation |
--shard |
Cross-machine split | Large suites in CI |
testSequencer |
Failure-first ordering | Default already optimizes feedback time |
--onlyChanged / --changedSince |
Run a subset | Pre-commit hooks, PR pipelines |
| Watchman | Incremental crawl | Large repos in watch mode |
Note
maxWorkersaccepts a percentage.getMaxWorkersresolves"50%"tofloor(0.5 × CPUs)(minimum 1). In watch mode Jest deliberately uses about half the CPUs to stay responsive.
Important
--detectOpenHandlesimplies--runInBandand is slow — use it to diagnose, not in normal runs.--detectLeaksis explicitly experimental and can produce false positives.
9. ECMAScript Modules (ESM)
Jest supports native ESM with caveats. Enable it by:
-
Running Node with the VM-modules flag:
node --experimental-vm-modules node_modules/jest/bin/jest.js -
Marking files as ESM — via
"type": "module"inpackage.json, a.mjsextension, orextensionsToTreatAsEsm:// jest.config.js module.exports = {extensionsToTreatAsEsm: ['.ts']};
Inside ESM tests, the jest object is imported rather than global:
import {jest} from '@jest/globals';
Warning
Native ESM support is still evolving. Mixed CJS/ESM graphs, named imports from CommonJS, and some transform interop edge cases remain rough. If you hit "can't import named imports from cjs modules", prefer default imports or a transform that produces interop shims.
10. Security Considerations
Jest executes your test code (and the modules it imports) with full Node.js privileges. Treat it as you would any code-execution tool.
- Untrusted code: Never run Jest over test files or
node_modulesyou do not trust.globalSetup,setupFiles, transformers, reporters, resolvers, and environments are all arbitrary modules executed by Jest. - Environment variables: Jest sets
NODE_ENV=testif unset.babel-jestreadsBABEL_ENV/NODE_ENV. Avoid leaking secrets into test logs (--silentsuppresses console output). - No network sandbox: The
nodeenvironment has unrestricted network/filesystem access. Mock external calls; do not let tests hit production services. - Snapshot review: Snapshots are committed code. Review snapshot diffs in PRs — a malicious or accidental snapshot update can mask a regression.
- Coverage of secrets:
collectCoverageFromglobs can pull files into reports; ensure config/secret files are excluded viacoveragePathIgnorePatterns.
Caution
Custom transformers and environments run before your test code and can read anything the Node process can. Pin and audit third-party Jest plugins like any other dependency.
11. Operations & Internal Troubleshooting
Diagnosing a stuck or non-exiting run
jest --detectOpenHandles --runInBand
Surfaces timers, sockets, and handles left open. Pair with teardown hooks. If Jest still hangs, --forceExit is a blunt last resort (it masks the underlying leak).
Inspecting resolved configuration
jest --showConfig
Prints the fully-merged GlobalConfig and per-project ProjectConfig — the ground truth for "why is Jest doing X". --debug prints a smaller diagnostic subset.
Clearing a corrupt cache
jest --clearCache
Deletes the configured cache directory. Do this after upgrading Jest or changing transform config if you see stale-transform symptoms.
Common internal errors
| Message | Meaning / Fix |
|---|---|
jest: No configuration found for any project. |
No config/jest key found — add one or pass --config |
Test environment <name> cannot be found. |
Environment package not installed (e.g. install jest-environment-jsdom) |
Both --runInBand and --maxWorkers were specified, only one is allowed. |
Remove one flag |
Cannot merge config in form of callback |
mergeConfig/defineConfig received a function; pass plain objects |
Module <x> in the <roots> option was not found. |
A roots/path option points at a missing directory |
Farm is ended, no more calls can be done to it |
A jest-worker pool received work after shutdown — usually a custom runner bug |
Unable to load resolver at <path> |
resolver path is wrong or the module throws on load |
Memory growth across runs
Reported for some Jest 29→30 upgrades (issue #15743). Mitigations: --workerIdleMemoryLimit to recycle heavy workers, --logHeapUsage to find the offending suite, drop large globals in afterEach, and consider --runInBand to isolate.
12. Building & Contributing
Jest is a Yarn-workspaces monorepo. The published jest binary is node ./packages/jest-cli/bin/jest.js.
# clone and install
git clone https://github.com/jestjs/jest
cd jest
yarn
# build all packages (TypeScript → CommonJS + d.ts)
yarn build
# run Jest's own test suite
yarn jest
# type-check
yarn typecheck
| Directory | Contents |
|---|---|
packages/ |
All published packages (the source of truth) |
e2e/ |
End-to-end fixtures and integration tests (each subfolder is a mini-project) |
examples/ |
Runnable example setups (React, Angular, TypeScript, snapshot, timers, …) |
website/ |
The Docusaurus documentation site, including versioned docs |
benchmarks/ |
Performance benchmarks |
scripts/ |
Build and maintenance tooling |
Note
Each package compiles independently. The
typecheck:testsscript type-checks a curated set of package test trees. When adding a public API, update both the implementation and thejest-typesdefinitions so consumers get correct typings.
13. Quick Reference
Default values at a glance
| Setting | Default |
|---|---|
| Test framework | jest-circus/runner |
| Environment | jest-environment-node |
| Sequencer | @jest/test-sequencer |
maxWorkers |
50% |
maxConcurrency |
5 |
testTimeout |
5000 ms |
coverageProvider |
babel |
coverageReporters |
json, text, lcov, clover |
moduleFileExtensions |
js, mjs, cjs, jsx, ts, mts, cts, tsx, json, node |
bail |
0 |
openHandlesTimeout |
1000 ms |
workerGracefulExitTimeout |
500 ms |
slowTestThreshold |
5 s |
| Config file search order | js → ts → mjs → mts → cjs → cts → json |
Config file precedence
--config <path|json>(CLI)jest.config.{js,ts,mjs,mts,cjs,cts,json}jestkey inpackage.json
Key environment variables
| Variable | Set by / read by |
|---|---|
JEST_WORKER_ID |
Set per worker (1-based) — use to isolate per-worker resources |
NODE_ENV |
Defaulted to test; read by babel-jest and haste map |
BABEL_ENV |
Read by babel-jest to select a Babel environment |