Skip to content
Latchkey

Jest "Cannot find module" - Fix Resolution Errors in CI

Jest could not resolve an import. Either the package was never installed, the file path is wrong (often a case mismatch that only matters on Linux), or a path alias is not mapped in the Jest config.

What this error means

A test file fails at collection with Cannot find module 'X' from 'Y'. It frequently passes locally on macOS but fails on a Linux CI runner because the filesystem there is case-sensitive.

Jest output
Cannot find module '@/utils/format' from 'src/components/Card.test.tsx'

  Require stack:
    src/components/Card.test.tsx

Diagnose it: flake, environment, or genuine failure?

Before debugging the assertion, establish whether the test is deterministic. A test that fails only in CI is usually order-dependent, time-dependent, or racing something, and fixing the assertion will not help.

Terminal
# does it fail in isolation?
npx vitest run path/to/file.test.ts

# is it order dependent? run the suite in a random order twice
npx vitest run --sequence.shuffle

# is it a race? run the same file repeatedly
for i in $(seq 1 20); do npx vitest run path/to/file.test.ts || break; done

Common causes

Path alias not mapped in Jest

A @/... alias works in your bundler and tsconfig paths, but Jest resolves modules itself and needs the same mapping in moduleNameMapper. Without it, the import is unresolvable.

Case-sensitive import on Linux

Importing ./Card when the file is card.tsx works on case-insensitive macOS/Windows but fails on a case-sensitive Linux runner.

Dependency not installed

The package is in devDependencies but CI ran npm ci --omit=dev, or it was never added to package.json, so it is absent from node_modules.

How to fix it

Map path aliases in Jest config

Mirror your tsconfig paths into moduleNameMapper so Jest resolves aliases the same way your build does.

jest.config.js
// jest.config.js
module.exports = {
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1',
  },
};

Fix the import case to match the file

  1. Compare the import path against the real filename, including capitalization.
  2. Rename the import (or the file) so they match exactly.
  3. Add eslint-plugin-import with import/no-unresolved to catch this before CI.

Install the missing dependency

Terminal
npm install <package>
# if it is needed for tests, ensure CI installs devDependencies (no --omit=dev)

CI-only causes worth ruling out

  • Runners have fewer cores than a laptop, so timing-sensitive tests that pass locally fail under contention.
  • No TTY and a different locale or timezone. Snapshot tests containing formatted dates or numbers are the usual casualty; pin TZ and LANG in the job.
  • Parallel workers sharing a database, a port, or a temp directory. Give each worker its own namespace.
  • Default timeouts calibrated on a fast machine. A cold runner is slower on first execution, especially before any cache warms.

How to prevent it

  • Keep moduleNameMapper in sync with tsconfig paths.
  • Develop or lint on a case-sensitive filesystem to catch case bugs early.
  • Commit the lockfile and run npm ci so installs are reproducible.

Frequently asked questions

What causes Jest "Cannot find module"?
There are 3 common causes: path alias not mapped in jest, case-sensitive import on linux, and dependency not installed. A @/... alias works in your bundler and tsconfig paths, but Jest resolves modules itself and needs the same mapping in moduleNameMapper.
How do I fix Jest "Cannot find module"?
There are 3 fixes depending on which cause you have: map path aliases in jest config, fix the import case to match the file, and install the missing dependency. Work through them in order, since the first is the most common.
What does Jest "Cannot find module" actually mean?
A test file fails at collection with Cannot find module 'X' from 'Y'.
How do I stop Jest "Cannot find module" happening again?
Keep moduleNameMapper in sync with tsconfig paths. The prevention section lists 3 changes that keep it from recurring.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card