TypeScript

Fix Jest Cannot find module on absolute path imports

Why an import that already matches moduleDirectories still throws Cannot find module: a failing test, then a passing one, for two different fixes.

Mahdi Ben RhoumaMahdi Ben Rhouma
7 min read

A project's moduleDirectories can already list src as a search path and the exact same import can still throw Cannot find module. The usual advice — "add src to moduleDirectories" — does not fix it, because that configuration is already there; the import string is what has to change, or a second configuration key alongside it.

TL;DR#

Jest's resolver, when moduleDirectories includes src, searches <project>/src/<the import string> for a bare import. An import written as src/views/app then makes Jest look for src/src/views/app, which does not exist — the src/ prefix is redundant and breaks resolution even though the directory is already configured. The accepted fix is to drop the prefix and import views/app instead; moduleDirectories does not change. Adding modulePaths: ["<rootDir>"] fixes the same case without touching the import, which is faster when many imports already carry the prefix. A project that has not configured moduleDirectories at all needs the config added, not the import rewritten — the two are different starting points, verified separately below.

The error#

text
Cannot find module 'src/views/app' from 'index.jsx'
 
  at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:179:17)
  at Object.<anonymous> (src/index.jsx:4:12)

This is from Stack Overflow #50863312 (206 votes, 363k+ views). The asker's package.json already configures jest.moduleDirectories as ["node_modules", "src"], and index.jsx imports AppContainer from 'src/views/app'. Every test that only touches relative imports passes; only the one absolute-looking import fails.

Reproduced on Node 22.23.4 with Jest 29.7.0 (node:22-alpine, 31 October 2026) with a two-file project, src/views/app.js exporting a function and src/index.js requiring it. With jest.moduleDirectories set to ["node_modules", "src"] in package.json and src/index.js doing require('src/views/app'), the suite fails with the identical message, Cannot find module 'src/views/app' from 'src/index.js'.

Why it happens#

The Jest configuration reference describes moduleDirectories as an array of directory names searched recursively up from the requiring module's location, and warns that setting it replaces the default list rather than adding to it — node_modules has to be listed explicitly alongside any other directory to keep resolving installed packages.

With moduleDirectories: ["node_modules", "src"], Jest's resolver takes the import string and, for each directory name in the list, looks for <ancestor-directory>/<name>/<import string>, walking up from the requiring file. For the import src/views/app that means it tries node_modules/src/views/app and src/src/views/app — not src/views/app, because the import string itself already starts with src/. Neither path exists, so Jest reports Cannot find module, even though the file sits exactly where src was configured to be searched.

For the import views/app, the same resolution tries node_modules/views/app (missing) and src/views/app (present), which is why the accepted answer's fix is to remove the prefix from the import rather than to touch the Jest config. The directory name in moduleDirectories is not supposed to be repeated inside the import string — it is already the thing being searched.

This is a different mechanism from a TypeScript path alias such as @/components/Button breaking under Jest, which goes through moduleNameMapper instead — see Fix tsconfig Paths Not Working in Next.js. It is also different from a project that has never configured moduleDirectories, roots or modulePaths at all: that one needs the configuration added, covered next.

Fix#

If moduleDirectories is already configured: drop the redundant prefix#

This is the asker's own case and the accepted answer. Leave the Jest configuration untouched and change only the import:

diff
- import AppContainer from 'src/views/app';
+ import AppContainer from 'views/app';

Reproduced: with moduleDirectories: ["node_modules", "src"] unchanged, changing only require('src/views/app') to require('views/app') turns the failing suite green:

text
PASS src/__tests__/index.test.js (9.652 s)
  ✓ resolves AppContainer (6 ms)
 
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total

Before checking this, confirm which directory name is already in moduleDirectories (jest --showConfig prints the resolved value) and strip exactly that prefix from the failing import — a project that configured moduleDirectories: ["node_modules", "app"] needs imports to start from inside app/, not src/.

If moduleDirectories has not been configured at all: add it#

A project that has no jest.moduleDirectories key, and imports with a bare bundler-style path such as views/app, fails for the more familiar reason: Jest's resolver defaults to searching only node_modules. Reproduced separately: the same two-file project with no jest key in package.json and require('views/app') fails with Cannot find module 'views/app' from 'src/index.js'. Adding only the configuration below, with no change to the import, turns it green:

json
{
  "jest": {
    "moduleDirectories": ["node_modules", "src"]
  }
}

node_modules must stay first in the array — moduleDirectories replaces Jest's default rather than extending it, so moduleDirectories: ["src"] on its own would stop every installed package from resolving.

Alternative: modulePaths, without touching the import#

The second answer on the thread (122 votes, more than the accepted answer's 78) points at roots (which directories Jest searches for test and module files at all, default ["<rootDir>"]) and modulePaths — an array of absolute paths, using the <rootDir> token, that the Jest docs describe as an alternative to setting the NODE_PATH environment variable — instead of changing the import:

json
{
  "jest": {
    "modulePaths": ["<rootDir>"],
    "moduleDirectories": ["node_modules", "src"]
  }
}

Reproduced: with the require('src/views/app') import left exactly as the asker wrote it, and moduleDirectories left unchanged, adding only modulePaths: ["<rootDir>"] turns the failing suite green. modulePaths treats <rootDir> itself as a resolution root, so src/views/app resolves as <rootDir>/src/views/app — the prefix that broke moduleDirectories resolution is exactly what modulePaths expects. This is the fix for a codebase with many src/...-prefixed imports already in place: one config addition instead of rewriting every import statement.

A third option reproduces as well: moduleNameMapper rewrites the same prefixed import to the real path with a single regular-expression rule, the same mechanism the Jest docs recommend for a @/ alias:

json
{
  "jest": {
    "moduleNameMapper": {
      "^src/(.*)$": "<rootDir>/src/$1"
    }
  }
}

It solves this case too, but it is one more mapping to keep in sync with the folder layout for what modulePaths or a prefix removal already fix in one line.

Verify the fix#

Re-run the suite that reported the error:

bash
npx jest

jest --showConfig prints the resolved moduleDirectories, roots and modulePaths, so a misread package.json key is visible immediately rather than only as another Cannot find module. If the suite still fails after removing the prefix, confirm the file actually sits inside the directory named in moduleDirectories — a typo in either the config or the import produces the identical error message.

One email a month — the latest explained errors

What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.

If the error changes#

Fixing this resolver mismatch does not change how Jest resolves TypeScript path aliases declared in tsconfig.json. If the project also uses @/components/...-style aliases and Jest still cannot find those, the missing piece is moduleNameMapper, not moduleDirectories — see Fix tsconfig Paths Not Working in Next.js. A project that compiles with tsc and runs the emitted JavaScript with plain Node, outside Jest, hits a related but distinct error covered in Fix Cannot find module defined in tsconfig paths at runtime: tsc leaves the alias untouched in the emitted require(), which Jest never sees because it transforms source on the fly instead of running compiled output.

A Vite project that fails with SyntaxError: Cannot use 'import.meta' outside a module instead of Cannot find module is hitting a separate CommonJS/ESM mismatch under Jest, not a resolver path problem — see Cannot use 'import.meta' outside a module: Jest + Vite fix.

None of this applies if the error names a .d.ts file or says TS2688 instead of Cannot find module: that is TypeScript's compiler rejecting a typeRoots entry at type-check time, a different tool and a different failure, covered in Fix TS2688: node_modules Is the Wrong typeRoots.

Either way, the fastest way to tell the two families apart is the exact wording of the error: Cannot find module '<string>' names the specifier Jest tried and failed to resolve, and that string is the first thing to compare against moduleDirectories, modulePaths and moduleNameMapper in turn, rather than guessing which one applies.

Further reading: Fix TransformStream is not defined in Jest.

Frequently Asked Questions

|

Have more questions? Contact us

Still stuck? Paste your error.

Paste the error message or stack trace — we check it against every fix and tool on the site.

Matching happens in your browser. When you search, a cleaned error signature is sent so we can spot errors we do not cover yet — never the raw text, your IP address or your e-mail. Do not paste passwords or keys. Details

Written by

Mahdi Ben Rhouma
Mahdi Ben Rhouma

Full-Stack Dev — Next.js & Supabase

Solo developer building SaaS products with Next.js and Supabase. Writing about production patterns the official docs skip.

Remote