TypeScript TS2307: Cannot find module 'X' or its corresponding type declarations
Cannot find module
Verified against TypeScript docs: Module Resolution, TypeScript handbook: Modules, TypeScript 5.5 release notes · Updated June 2026
> quick_fix
TypeScript can't find the module you're importing. Either the package isn't installed, the type declarations are missing, or the import path is wrong. Run npm install for the package, install @types/packagename if types are separate, or check your tsconfig.json moduleResolution setting.
// TS2307: Cannot find module 'lodash' or its corresponding type declarations
import _ from 'lodash'
// Fix 1: install the package
// npm install lodash
// Fix 2: install type declarations
// npm install -D @types/lodash
// Fix 3: if no types exist, declare the module
// In a .d.ts file:
declare module 'lodash'What causes this error
TS2307 fires when TypeScript's module resolution algorithm can't locate the file or package referenced by an import statement. This happens when: the npm package isn't installed, the package exists but has no TypeScript type declarations (no index.d.ts and no @types package), the import path is wrong (typo, missing file extension, wrong relative path), or the tsconfig.json moduleResolution setting doesn't match the project's module system.
How to fix it
- 01
step 1
Check if the package is installed
The most common cause is a missing npm install. Check node_modules for the package and your package.json for the dependency.
// Check if installed: // ls node_modules/lodash // If missing: // npm install lodash // For dev-only packages: // npm install -D vitest - 02
step 2
Install @types declarations for untyped packages
Many JavaScript packages don't include TypeScript declarations. The DefinitelyTyped project provides @types/packagename packages for most popular libraries. Install them as dev dependencies.
// Package has no built-in types — install from DefinitelyTyped // npm install -D @types/express // npm install -D @types/node // npm install -D @types/react // Check if @types exists: // npm info @types/packagename // Some packages bundle their own types (no @types needed): // zod, drizzle-orm, hono, effect — check for 'types' in package.json - 03
step 3
Fix relative import paths
For local file imports, verify the path is correct. TypeScript resolves relative imports from the importing file's location. Common mistakes: missing .js extension (required in ESM), wrong directory depth, importing a directory without an index file.
// Wrong: file is at ./utils/helpers.ts import { parse } from './util/helpers' // typo in directory name import { parse } from '../utils/helpers' // wrong depth // Correct import { parse } from './utils/helpers' // ESM with moduleResolution: 'nodenext' requires .js extension import { parse } from './utils/helpers.js' // .js even for .ts files - 04
step 4
Check tsconfig.json moduleResolution
The moduleResolution setting controls how TypeScript looks up imports. Mismatches between your module system and resolution strategy cause TS2307. For modern projects: use 'bundler' for Vite/webpack/esbuild, 'nodenext' for Node.js ESM, or 'node' for Node.js CommonJS.
// tsconfig.json — common configurations // For Vite, Next.js, or bundled projects: { "compilerOptions": { "moduleResolution": "bundler", "module": "esnext" } } // For Node.js ESM (package.json has "type": "module"): { "compilerOptions": { "moduleResolution": "nodenext", "module": "nodenext" } } // For Node.js CommonJS: { "compilerOptions": { "moduleResolution": "node", "module": "commonjs" } } - 05
step 5
Declare modules for untyped packages or non-code imports
If no @types package exists and you can't type the module fully, create a declaration file (.d.ts) with a module declaration. This is also required for non-code imports like CSS modules, images, and SVGs.
// src/types/declarations.d.ts // Minimal declaration for an untyped package declare module 'some-untyped-lib' { export function doThing(input: string): string export default function main(): void } // CSS modules declare module '*.module.css' { const classes: Record<string, string> export default classes } // Image imports (Vite/webpack) declare module '*.png' { const src: string export default src } // SVG as React component (SVGR) declare module '*.svg' { import type { FC, SVGProps } from 'react' const ReactComponent: FC<SVGProps<SVGSVGElement>> export default ReactComponent }
How to verify the fix
- Run tsc --noEmit and confirm TS2307 no longer appears
- Verify the import resolves to the correct file (hover in VS Code to check)
- Ensure .d.ts files are included in tsconfig.json's include or typeRoots
Why TS2307 happens at the runtime level
TS2307 is emitted by the module resolver in src/compiler/moduleNameResolver.ts when none of the resolution strategies find a matching file. TypeScript tries multiple locations in sequence: relative paths check the file system directly; bare specifiers check node_modules with various extensions (.ts, .tsx, .d.ts, .js, /index variants); and packages with 'exports' fields are resolved through the exports map. The resolution strategy is controlled by moduleResolution in tsconfig.json, and each strategy has different rules for extensions, index files, and package.json fields. If every strategy fails, TS2307 is emitted.
Common debug mistakes for TS2307
- Forgetting to run npm install after cloning a repo or adding a new dependency to package.json.
- Using moduleResolution 'node' with a project that uses package.json 'exports' fields — switch to 'bundler' or 'nodenext'.
- Importing from a path alias (like @/utils) without configuring 'paths' in tsconfig.json.
- Missing .js extension on relative imports when using moduleResolution 'nodenext' — TypeScript requires .js even for .ts source files.
- Overriding typeRoots in tsconfig.json without including node_modules/@types, which breaks all @types resolution.
When TS2307 signals a deeper problem
Chronic TS2307 errors across a project usually indicate a mismatch between the build tool's module resolution and TypeScript's configuration. Bundlers like Vite and webpack resolve imports differently than TypeScript — they support path aliases, CSS imports, and extensionless paths that TypeScript doesn't understand by default. The fix is alignment: set moduleResolution to 'bundler' for bundled projects, configure paths in tsconfig.json to match bundler aliases, and add declaration files for non-code imports. When TypeScript and the bundler agree on how imports resolve, TS2307 stops being a constant irritant.
Editor's take
TS2307 is the most frustrating TypeScript error for beginners because it has nothing to do with your code's logic — it's a tooling configuration problem. Your code might be perfectly correct, but TypeScript can't find the file you're importing, so it refuses to compile. The fix is almost always one of four things: install the package, install its @types, fix the import path, or fix your tsconfig.json. But knowing which one requires understanding how module resolution actually works.
The moduleResolution setting is the most impactful tsconfig option for TS2307. The 'bundler' option, added in TypeScript 5.0, finally solved the chronic mismatch between how bundlers and TypeScript resolve imports. Before 'bundler', projects using Vite or webpack had to choose between 'node' (which didn't support package.json exports) and 'nodenext' (which required .js extensions on every import). Now 'bundler' gives you exports support without extension requirements — matching what bundlers actually do.
The '@types' ecosystem is TypeScript's solution for JavaScript packages that ship without type declarations. When you import lodash and get TS2307, it's not because lodash isn't installed — it's because lodash ships plain JavaScript with no .d.ts files. The @types/lodash package from DefinitelyTyped provides those declarations. This split is confusing but practical: library authors who don't use TypeScript don't need to maintain types, and the community can update them independently.
The most subtle TS2307 trigger is path aliases. Writing import { utils } from '@/lib/utils' requires both a bundler alias and a TypeScript paths mapping in tsconfig.json. Missing either one causes TS2307 in the editor but the build might still work — or vice versa. Keep them in sync, or use vite-tsconfig-paths to derive one from the other.
By Bikram Nath · Curator · Updated June 2026
Frequently asked questions
Why do I get TS2307 for .css, .svg, or .png imports?
TypeScript only understands .ts, .tsx, .js, .jsx, and .json files by default. Non-code imports (CSS, images, SVGs) are handled by your bundler (Vite, webpack, esbuild) at build time, but TypeScript doesn't know about them. You need a declaration file (.d.ts) that tells TypeScript what type these imports produce. Most frameworks provide these declarations — Next.js has next-env.d.ts, Vite has vite/client. If yours doesn't, create a declarations.d.ts in your src directory.
What's the difference between moduleResolution 'node', 'nodenext', and 'bundler'?
'node' uses Node.js CommonJS resolution: no file extensions required, checks index.js in directories, looks in node_modules. 'nodenext' uses Node.js ESM resolution: requires .js file extensions on relative imports, respects package.json 'exports' fields, and supports both ESM and CJS. 'bundler' is like 'nodenext' but doesn't require file extensions — it assumes a bundler will resolve imports. Use 'bundler' for Vite/webpack projects, 'nodenext' for Node.js libraries, and 'node' only for legacy CommonJS projects.
The package is installed but TS2307 still fires. What's wrong?
Several possibilities: the package's types are in a subpath (import from 'pkg/subpath' but types only cover 'pkg'), the package uses 'exports' in package.json and your moduleResolution doesn't support it (switch to 'bundler' or 'nodenext'), there's a monorepo workspace resolution issue (check that the workspace package is linked), or your tsconfig.json 'typeRoots' overrides the default and doesn't include node_modules/@types. Check the package's package.json for 'types' or 'exports' fields.