How to Fix TypeScript Cannot Find Module Error
On this page
How to Fix TypeScript Cannot Find Module Error
Few errors are as common — or as frustrating — as TypeScript's Cannot find module 'X' or its corresponding type declarations. It shows up when you add a new dependency, refactor your folder structure, import a CSS file, or move a project to a new machine. The good news is that this error almost always comes down to one of a handful of root causes. This guide walks through each of them with concrete fixes so you can get back to writing code.
What the Error Actually Means
When you write import { foo } from 'some-module', the TypeScript compiler (tsc) tries to do two things:
- Resolve the module — figure out which file on disk
'some-module'points to. - Find its types — locate a
.d.tsdeclaration file describing the module's shape.
If either step fails, you get Cannot find module. The key insight is that this is a compile-time error about resolution and types, not a runtime error. Your code might even run fine with a bundler while TypeScript still complains. Knowing which of the two steps failed is the fastest path to a fix.
Fix 1: Install the Missing Package
The most common cause is the simplest: the package isn't installed. Check your node_modules and package.json:
npm ls some-module
If it's missing, install it:
npm install some-module
Sometimes the package is installed but node_modules is stale or corrupted — common after switching branches or pulling new changes. A clean reinstall fixes a surprising number of these errors:
rm -rf node_modules package-lock.json
npm install
Fix 2: Install Type Declarations (@types)
Many JavaScript libraries don't ship their own TypeScript types. For these, the community maintains type packages under the @types/ scope on DefinitelyTyped. If you see an error like Could not find a declaration file for module 'lodash', install the matching types:
npm install --save-dev @types/lodash
The naming convention is @types/<package-name>. For scoped packages like @scope/pkg, the types package is @types/scope__pkg (note the double underscore).
If no @types package exists and the library doesn't bundle types, you can declare the module yourself. Create a file like src/types/declarations.d.ts:
declare module 'untyped-library';
This silences the error by treating the module as any. For better safety, you can flesh out the declaration with the actual exports you use:
declare module 'untyped-library' {
export function doThing(input: string): number;
export const version: string;
}
Fix 3: Check Your Import Path
For your own files (relative imports), a Cannot find module './utils/helper' error usually means the path is wrong. Verify:
- The file exists at the path you think it does.
- Case matches exactly. macOS and Windows filesystems are case-insensitive, but Linux (and your CI server) is not. Importing
./Helperwhen the file ishelper.tswill work locally and break in CI. This is one of the most common "works on my machine" bugs. - The extension is correct. TypeScript resolves
.ts,.tsx, and.d.tsautomatically, but with"moduleResolution": "node16"or"nodeNext", you may need to write explicit.jsextensions in your import statements even for TypeScript files.
Fix 4: Configure Path Aliases in tsconfig.json
If you use path aliases like import { x } from '@/components/Button', TypeScript needs to know how to resolve @/. Define them in tsconfig.json under compilerOptions:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}
The critical detail people miss: TypeScript's paths only affects type checking, not the actual build or runtime. Your bundler or runtime needs the same alias configured separately. For Webpack use resolve.alias; for Vite use resolve.alias; for Jest use moduleNameMapper; for Node use a loader like tsconfig-paths. If types resolve but runtime fails (or vice versa), this mismatch is usually why.
Fix 5: Align moduleResolution and module Settings
Modern TypeScript is strict about module resolution strategy. Check these compilerOptions:
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "bundler",
"esModuleInterop": true,
"resolveJsonModule": true
}
}
A few guidelines:
"moduleResolution": "bundler"is the modern default for projects using Vite, Webpack, or esbuild. It mirrors how bundlers resolve modules and is the most forgiving."node16"/"nodeNext"enforce Node's ESM rules, including mandatory file extensions in imports."resolveJsonModule": trueis required if youimport data from './data.json'."esModuleInterop": truefixes errors when importing CommonJS modules with default imports.
If you recently upgraded TypeScript and started seeing module errors, a changed default for moduleResolution is a likely culprit.
Fix 6: Handle Non-Code Imports (CSS, Images, SVG)
Importing assets like import styles from './app.css' or import logo from './logo.svg' produces Cannot find module because TypeScript has no idea what those files export. Declare them once in a .d.ts file:
// assets.d.ts
declare module '*.css';
declare module '*.svg' {
const content: string;
export default content;
}
declare module '*.png';
Make sure this file is within your include glob (see below) so TypeScript actually picks it up.
Fix 7: Verify include and exclude
If a file or its types live outside what tsconfig.json includes, TypeScript ignores them. Check the include and exclude arrays:
{
"include": ["src/**/*", "types/**/*"],
"exclude": ["node_modules", "dist"]
}
Your custom .d.ts declaration files must fall inside an include path. A common mistake is putting declarations in a folder that the glob doesn't cover.
Fix 8: Restart the TypeScript Server
If you've made changes and the error persists in your editor but not on the command line, your editor's TypeScript language server is using a stale cache. In VS Code, open the command palette (Cmd/Ctrl + Shift + P) and run "TypeScript: Restart TS Server." This resolves a large share of phantom errors after installing packages or editing tsconfig.json. Confirm the real state by running tsc --noEmit in the terminal — that's the source of truth.
A Systematic Debugging Checklist
When you hit the error, work through it in this order:
- Run
tsc --noEmitto confirm the error outside your editor. - Check the package is installed (
npm ls <module>). - Check whether you need
@types/<module>. - Verify the import path and its exact casing.
- Confirm any path aliases exist in both
tsconfig.jsonand your bundler/runtime. - Review
moduleResolution,module, andesModuleInterop. - Add
declare modulestubs for assets or untyped packages. - Confirm declaration files are inside
include. - Restart the TS server.
Following the list top to bottom isolates the cause quickly instead of guessing.
FAQ
Why does my code run fine but TypeScript still shows the error?
Bundlers and the TypeScript type checker resolve modules independently. Your bundler may find the module while tsc can't, typically because of mismatched path aliases or a missing @types package. Both need to be satisfied.
What's the difference between "Cannot find module" and "Could not find a declaration file"?
"Cannot find module" means TypeScript can't locate the module at all. "Could not find a declaration file" means it found the JavaScript but has no types — fix that by installing @types/<package> or writing a declare module stub.
Do I need file extensions in my imports?
It depends on moduleResolution. With "bundler" or the legacy "node", no. With "node16"/"nodeNext", you must include explicit extensions (usually .js, even for .ts source files).
Why does it work locally but break in CI?
Almost always a case-sensitivity issue. macOS and Windows ignore filename casing; Linux CI runners don't. Make every import's casing match the file on disk exactly.
How do I fix it for CSS or image imports?
Add an ambient declaration file with declare module '*.css'; (and similar for other asset types), and make sure it's covered by your tsconfig.json include glob.
Wrapping Up
The Cannot find module error feels opaque, but it's really TypeScript telling you that either the module or its types couldn't be found. Once you know which half failed, the fix is mechanical: install the package, add @types, correct a path, configure an alias in both places, or declare an ambient module. Keep the checklist above handy, and the error becomes a quick speed bump rather than a roadblock.