# Jest Admin & Architecture Guide

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 under `packages/`. 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`:

1. The CLI (`jest-cli`) parses arguments and hands off to `jest-core`.
2. `jest-config` resolves and normalizes configuration into a frozen **global config** plus one **project config** per project.
3. `jest-core` builds a `SearchSource` over a `jest-haste-map` file index to find test files, orders them with a **test sequencer**, then dispatches them.
4. A **runner** (`jest-runner` by default) executes each test file — in-process or across a `jest-worker` pool.
5. For each file, a `jest-runtime` sandbox provides module loading, mocking, and the test environment (`jest-environment-node` or `jest-environment-jsdom`).
6. The **test framework** (`jest-circus` by default) runs the `describe`/`test` blocks; assertions go through `expect`.
7. Results flow back through `jest-test-result` to 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

```text
        $ 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 to `jest-transform`/`babel-jest`; a snapshot mismatch to `jest-snapshot`; a parallelism issue to `jest-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 of `projects`, 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`.

```text
<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 `modulePathIgnorePatterns` and (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 `engines` range. 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`:

```javascript
// my-transformer.js
module.exports = {
  process(sourceText, sourcePath, options) {
    return {code: compile(sourceText)};
  },
  getCacheKey(sourceText, sourcePath, options) {
    return createHash(sourceText + options.configString);
  },
};
```

```javascript
// 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:

```javascript
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"*). Always `await 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:

```javascript
class MyReporter {
  onRunStart(results, options) {}
  onTestStart(test) {}
  onTestResult(test, testResult, aggregatedResult) {}
  onRunComplete(contexts, results) {}
}
module.exports = MyReporter;
```

```javascript
// 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.

```javascript
// 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:

```bash
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 `projects` glob 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`.

```bash
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`:

```bash
# 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

```bash
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 default `50%` because CI containers frequently misreport CPU count. Measure both.

> [!CAUTION]
> The `JEST_WORKER_ID` environment variable is set by Jest inside each worker (starting at `1`). Use it to give each worker an isolated resource (e.g. a database schema `test_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]
> `maxWorkers` accepts a percentage. `getMaxWorkers` resolves `"50%"` to `floor(0.5 × CPUs)` (minimum 1). In watch mode Jest deliberately uses about half the CPUs to stay responsive.

> [!IMPORTANT]
> `--detectOpenHandles` implies `--runInBand` and is slow — use it to diagnose, not in normal runs. `--detectLeaks` is explicitly experimental and can produce false positives.

---

## 9. ECMAScript Modules (ESM)

Jest supports native ESM with caveats. Enable it by:

1. Running Node with the VM-modules flag:

   ```bash
   node --experimental-vm-modules node_modules/jest/bin/jest.js
   ```

2. Marking files as ESM — via `"type": "module"` in `package.json`, a `.mjs` extension, or `extensionsToTreatAsEsm`:

   ```javascript
   // jest.config.js
   module.exports = {extensionsToTreatAsEsm: ['.ts']};
   ```

Inside ESM tests, the `jest` object is imported rather than global:

```javascript
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_modules` you do not trust. `globalSetup`, `setupFiles`, transformers, reporters, resolvers, and environments are all arbitrary modules executed by Jest.
- **Environment variables:** Jest sets `NODE_ENV=test` if unset. `babel-jest` reads `BABEL_ENV`/`NODE_ENV`. Avoid leaking secrets into test logs (`--silent` suppresses console output).
- **No network sandbox:** The `node` environment 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:** `collectCoverageFrom` globs can pull files into reports; ensure config/secret files are excluded via `coveragePathIgnorePatterns`.

> [!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

```bash
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

```bash
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

```bash
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`.

```bash
# 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:tests` script type-checks a curated set of package test trees. When adding a public API, update both the implementation and the `jest-types` definitions 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

1. `--config <path|json>` (CLI)
2. `jest.config.{js,ts,mjs,mts,cjs,cts,json}`
3. `jest` key in `package.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 |

---

_Generated June 2026 from jestjs/jest at 4c3091b. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
