Skip to content
compiler.dev

Jest Slow? How to Speed Up Jest Tests

If Jest is slow, the usual culprits are a slow TypeScript transform, too many or too few workers, heavy module imports repeated in every test file, and a single CI job running everything. This guide shows how to speed up Jest tests, including how to speed up Jest tests with TypeScript and how Jest test sharding works with --shard. It is part of the slow e2e tests cluster, which also covers slow integration tests.

Find out why Jest is slow

Start with numbers.

npx jest --verbose                 # per-test time
npx jest --listTests | wc -l       # how many files
npx jest --logHeapUsage            # memory per test file
npx jest --detectOpenHandles       # why it will not exit

Jest prints a slow-test warning for individual tests over five seconds by default. Look for two patterns: a few very slow files (fix those), or a large fixed cost per file (module loading and transform), which hits every file.

Fix the transform first

Type-checking transforms are the biggest cause for TypeScript projects. ts-jest type-checks each file by default. Either turn that off and type-check once with tsc --noEmit in a separate job, or switch to a transpile-only transformer such as @swc/jest:

// jest.config.js
module.exports = {
  transform: {
    "^.+\\.(t|j)sx?$": ["@swc/jest"],
  },
};

With ts-jest, set isolatedModules: true (or diagnostics: false) to skip type-checking per file. Keep type-checking in CI as its own parallel job, so correctness is unchanged.

Set workers deliberately

Jest runs test files in parallel worker processes. By default it uses cores minus one. On a 2-vCPU CI runner that is one worker, so the suite is effectively serial. Set it explicitly:

npx jest --maxWorkers=100%     # all cores, good on a CI runner dedicated to tests
npx jest --maxWorkers=50%      # leaves room for a dev machine
npx jest --runInBand           # one process; can be faster for tiny suites

For very small suites --runInBand avoids worker start-up. For big suites the right number is close to the core count. Memory matters too: if workers are killed, lower the count or raise the runner's RAM.

Cut per-file overhead

  • Barrel files: importing a package's index.ts can load hundreds of modules. Import from the specific file in tests.
  • Heavy setup: move expensive setup to globalSetup (runs once) rather than setupFilesAfterEnv (which runs before every test file).
  • Test environment: jsdom is slower to create than node. Use @jest-environment node for tests that do not touch the DOM.
  • Cache: Jest's transform cache is on by default. In CI, cache the cacheDirectory (npx jest --showConfig | grep cacheDirectory) with actions/cache, keyed on the lockfile and config. See GitHub Actions caching.
  • Changed files only: --onlyChanged or --changedSince=origin/main runs tests related to changes. Good for PR checks; keep a full run on main.

Jest test sharding

Jest has built-in sharding since version 28. --shard=index/count runs one slice of the test files:

npx jest --shard=1/4
npx jest --shard=2/4

In GitHub Actions run one slice per matrix job:

jobs:
  jest:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        shard: [1, 2, 3, 4]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22, cache: npm }
      - run: npm ci
      - run: npx jest --ci --maxWorkers=100% --shard=${{ matrix.shard }}/4

Sharding is by test file, not by duration, so one shard can be slower if it receives the big files. If shards are uneven, split large files or use a duration-based splitter. Coverage needs merging; the test sharding guide shows how, and the planner estimates the number of shards.

Slow integration tests inside Jest

If tests hit a database, make them cheap. Create the schema once in globalSetup, give each worker its own database (JEST_WORKER_ID is set in each worker), and wrap each test in a transaction that rolls back. Avoid sleep; use jest.useFakeTimers() for time-based logic.

When Jest itself is the bottleneck

Some teams move to Vitest for faster start-up; see Vitest slow for what to check there, since it has its own slow paths. Migration is a project, not a flag, so fix the transform and workers first.

Give CI more CPU

Test suites with many files scale with cores. If workers are limited by a 2-vCPU runner, compare options in faster GitHub Actions runners. compiler.dev was faster than GitHub's 2-core runner on 15 of 19 benchmarked stacks, by 1.1 to 3 times, and comparison mode measures your own jobs. The wider picture is in the slow CI hub.

FAQ

How do I speed up Jest tests?

Switch to a transpile-only transform, set --maxWorkers for your machine, cut per-file imports, cache the Jest cache directory in CI and shard across jobs with --shard.

How do I speed up Jest tests with TypeScript?

Use @swc/jest or ts-jest with isolatedModules, and run tsc --noEmit as a separate parallel job.

Does Jest support test sharding?

Yes, from Jest 28: jest --shard=1/3. It splits by file, so balance may be uneven.

Why is Jest slower in CI than locally?

Fewer cores (so fewer workers), an empty transform cache and often a type-checking transform. Fix each in turn.

Made by compiler.dev. Free tools · Pricing