How to fix Cannot find module './X' in TypeScript

TypeScriptBEGINNERMEDIUMUpdated Dec 8, 2025· 185 views

This error occurs when TypeScript cannot resolve a relative module import path, usually due to incorrect file paths, missing file extensions, case sensitivity issues, or misconfigured tsconfig.json. The fix involves verifying the import path, checking the actual file location, and configuring module resolution settings correctly.

Quick fix

Fixes TS2307

import { MyComponent } from './components/MyComponent';
  1. Verify the file path matches exactly
  2. Add the correct file extension
  3. Check case sensitivity of filenames
  4. Fix relative path navigation
typescript — error
import { MyComponent } from './components/MyComponent';
Cannot find module './X'

What this error means

This error means TypeScript's module resolution system cannot find the module you're trying to import with a relative path like `import { something } from './path/to/module'`. TypeScript resolves relative imports from the location of the current file, looking for a matching file with the specified path. When the file doesn't exist at that path, TypeScript raises this error. The error can occur during: - Development (in your editor with TypeScript Language Server) - Type checking (`tsc --noEmit`) - Compilation (`tsc`) - Build processes (webpack, Next.js, Vite, etc.) Common reasons include: 1. The actual file path doesn't match the import statement 2. File extension is missing or incorrect (.ts, .tsx, .js, etc.) 3. Typo in the file or folder name 4. Case sensitivity mismatch (on case-sensitive filesystems) 5. moduleResolution setting not configured correctly 6. The file exists but is outside the compiled directory structure

Typical symptoms

  • Red squiggly underline in your editor showing 'Cannot find module'
  • TypeScript compiler fails with TS2307 error
  • Import statement works in one environment but fails in another
  • Error appears after refactoring or moving files
  • IDE autocomplete doesn't suggest the module
  • Relative import works for some modules but not others
  • Error message shows the exact path TypeScript cannot find
  • Compilation succeeds but runtime fails to load the module

Common causes

  1. File path in the import statement doesn't match the actual file location
  2. File extension (.ts, .tsx, .js, .json) is missing from the import
  3. Filename has different casing (Windows is case-insensitive, Linux is case-sensitive)
  4. File was renamed, moved, or deleted but import statement wasn't updated
  5. Incorrect relative path (too many ../, not enough levels, wrong direction)
  6. Module is outside the src/ directory or compilation context
  7. tsconfig.json has incorrect baseUrl or paths configuration
  8. moduleResolution is set to 'classic' instead of 'node'
  9. Importing from a .d.ts declaration file that's not properly set up
  10. TypeScript version doesn't support the syntax or module format you're using

How to fix "Cannot find module './X'"

1Verify the file path matches exactly

First, confirm the file you're importing actually exists at the specified path:

1. Look at the import statement:

typescript
import { MyComponent } from './components/MyComponent';

2. From the current file, navigate to the relative path:
- If you're in src/pages/home.ts
- The import looks for: src/pages/components/MyComponent

3. Verify the file exists:
- Check if src/pages/components/MyComponent.ts exists
- Or src/pages/components/MyComponent.tsx

Use your terminal to check:

bash
# From project root, list the target directory
ls -la src/pages/components/

# Check the exact filename
ls -la src/pages/components/MyComponent*

If the file doesn't exist, the import path is wrong.

2Add the correct file extension

TypeScript imports often need file extensions. Check your import statement:

Without extension (may fail):

typescript
import { MyComponent } from './components/MyComponent';

With extension (more reliable):

typescript
import { MyComponent } from './components/MyComponent.ts';
// or for React:
import { MyComponent } from './components/MyComponent.tsx';

TypeScript resolution order (when extension is omitted):
1. MyComponent.ts
2. MyComponent.tsx
3. MyComponent.d.ts
4. MyComponent/index.ts
5. MyComponent/index.tsx
6. MyComponent/index.d.ts

Solution: Either add the extension explicitly, or rely on TypeScript's resolution order.

For Node modules and npm packages (non-relative imports), omit the extension:

typescript
import React from 'react';  // Correct
import React from 'react.ts';  // Wrong
3Check case sensitivity of filenames

On Windows and macOS, filenames are case-insensitive. On Linux and CI/CD servers, they're case-sensitive.

This often causes issues:
- You import: ./mycomponent
- Actual file: MyComponent.ts
- Works on Windows, fails on Linux

Fix: Match the exact case:

typescript
// Wrong (will fail on Linux):
import { MyComponent } from './mycomponent';

// Correct:
import { MyComponent } from './MyComponent';

Enable strict case checking in tsconfig.json:

json
{
  "compilerOptions": {
    "forceConsistentCasingInFileNames": true
  }
}

This makes your IDE warn you about case mismatches, catching the issue before you push to production.

Check actual filenames:

bash
# List files with exact case
ls -la src/components/ | grep -i mycomponent

# Find the file
find src -name "*mycomponent*" -o -name "*MyComponent*"
4Fix relative path navigation

Relative paths use ./ and ../ to navigate. Make sure your path has the right depth:

Example file structure:

bash
src/
├── pages/
│   └── home.ts
├── components/
│   └── Header.ts
└── utils/
    └── helpers.ts

From home.ts, import Header:

typescript
// Wrong (looking in wrong directory):
import { Header } from './Header';  // Looks in src/pages/, not src/components/

// Correct (go up one level, then into components):
import { Header } from '../components/Header';

From home.ts, import helpers:

typescript
// Correct:
import { someHelper } from '../utils/helpers';

Rules:
- ./file = same directory
- ../file = parent directory
- ../../file = grandparent directory
- ./subdir/file = subdirectory of current directory

Debug your path:

bash
# Current file: src/pages/home.ts
# Target file: src/components/Header.ts

# From src/pages/, count steps to src/components/:
# 1. Go up: ../ (now in src/)
# 2. Go into: components/ (now in src/components/)
# Result: ../components/Header
5Configure moduleResolution in tsconfig.json

TypeScript needs the correct module resolution strategy. Check your tsconfig.json:

For Node.js projects (most common):

json
{
  "compilerOptions": {
    "moduleResolution": "node",
    "module": "commonjs",
    "target": "es2020"
  }
}

For ES modules or modern projects:

json
{
  "compilerOptions": {
    "moduleResolution": "node",
    "module": "esnext",
    "target": "es2020"
  }
}

If moduleResolution is "classic" (very old), change it to "node":

json
// Wrong (old):
{
  "compilerOptions": {
    "moduleResolution": "classic"
  }
}

// Correct:
{
  "compilerOptions": {
    "moduleResolution": "node"
  }
}

For bundlers like Vite or webpack:

json
{
  "compilerOptions": {
    "moduleResolution": "bundler",
    "module": "esnext",
    "target": "es2020"
  }
}

Verify your setting:

bash
# Check current tsconfig.json
cat tsconfig.json | grep -A 5 compilerOptions
6Use path aliases instead of relative imports (recommended)

For complex folder structures, path aliases are cleaner than relative imports.

Configure in tsconfig.json:

json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@components/*": ["src/components/*"],
      "@utils/*": ["src/utils/*"],
      "@pages/*": ["src/pages/*"],
      "@/*": ["src/*"]
    },
    "moduleResolution": "node"
  }
}

Then use in your code:

typescript
// Instead of:
import { Header } from '../../../components/Header';
import { helpers } from '../../utils/helpers';

// Use cleaner aliases:
import { Header } from '@components/Header';
import { helpers } from '@utils/helpers';

Benefits:
- Easier to read and refactor
- Path changes don't break imports when moving files
- IDE autocomplete works better
- Less error-prone than counting ../

Make sure bundler supports it:

- Next.js: Automatically resolves paths from tsconfig.json
- Vite: Works out of the box
- Webpack: May need tsconfig-paths-webpack-plugin
- Node.js: Needs tsconfig-paths or module-alias package

7Check if TypeScript Language Server needs restart

Sometimes your IDE's TypeScript server gets out of sync with your files. Restart it:

In VS Code:

1. Press Ctrl+Shift+P (Windows/Linux) or Cmd+Shift+P (Mac)
2. Type: "TypeScript: Restart TS Server"
3. Press Enter

Or reload the window:
1. Ctrl+Shift+P → "Developer: Reload Window"

In WebStorm/IntelliJ:

1. Go to File > Invalidate Caches
2. Choose Invalidate and Restart

Check TypeScript version:

bash
# Verify TypeScript is installed
npx tsc --version

# Update TypeScript if needed
npm install --save-dev typescript@latest

# Or globally
npm install -g typescript@latest

Clear node_modules and reinstall:

bash
# Clear cache
npm cache clean --force

# Reinstall everything
rm -rf node_modules package-lock.json
npm install
8Verify the file is exported correctly

If the file exists and the path is correct, the file might not be exporting what you're trying to import.

Check the target file exists and exports:

typescript
// MyComponent.ts - CORRECT (default export)
export default function MyComponent() {
  return <div>Hello</div>;
}

// Usage:
import MyComponent from './MyComponent';
typescript
// MyComponent.ts - CORRECT (named export)
export function MyComponent() {
  return <div>Hello</div>;
}

// Usage:
import { MyComponent } from './MyComponent';
typescript
// MyComponent.ts - WRONG (no export)
function MyComponent() {
  return <div>Hello</div>;
}

// This will fail:
import { MyComponent } from './MyComponent';  // Error: not exported!

Fix: Add export if missing:

typescript
// Add one of these to MyComponent.ts

// Option 1: Named export
export function MyComponent() { ... }

// Option 2: Default export
export default function MyComponent() { ... }

// Option 3: Export after definition
function MyComponent() { ... }
export { MyComponent };

Advanced notes

### Type Declaration Files (.d.ts)

If you're importing from a .d.ts file, TypeScript has specific rules:

typescript
// utils.d.ts
declare function helper(): void;
export { helper };

// Correct import:
import { helper } from './utils';  // OR './utils.d.ts'

### Module Formats Mismatch

If you're mixing module formats, you may see this error:

typescript
// tsconfig.json
{
  "module": "commonjs",  // Compile to CommonJS
  "target": "es2020"
}

// source.ts (ESM syntax)
import { something } from './other';  // Error if other.ts isn't found

Solution: Use the same module syntax throughout your project.

### Barrel Exports (index.ts)

A common pattern is to re-export from an index file:

typescript
// src/components/index.ts (barrel export)
export { Header } from './Header';
export { Footer } from './Footer';
export { Button } from './Button';

// Usage:
import { Header, Footer } from './components';  // Imports from index.ts

TypeScript automatically looks for index.ts when importing a directory.

### Monorepo and Workspace Imports

In monorepo projects, configure paths for workspace packages:

json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@my-org/shared/*": ["packages/shared/src/*"],
      "@my-org/utils/*": ["packages/utils/src/*"]
    }
  }
}

### Debugging with --traceResolution

Use TypeScript's built-in debugging:

bash
# See exactly how TypeScript resolves modules
npx tsc --traceResolution --noEmit 2>&1 | head -50

This shows the exact resolution path and why it fails.

### Node16/NodeNext Module Resolution

For modern Node.js versions, use newer resolution:

json
{
  "compilerOptions": {
    "moduleResolution": "node16",
    "module": "es2020"
  }
}

This strictly enforces ES module rules and may reveal real issues with your imports.

### Source Maps and Debugging

If the error appears only at runtime but not in TypeScript:

json
{
  "compilerOptions": {
    "sourceMap": true,  // Generate source maps for debugging
    "strict": true      // Enable strict type checking
  }
}

Run with source maps to trace the real import path:

bash
node --enable-source-maps dist/index.js

Frequently asked questions

What does "TS2307" mean?
/path/to/module'. TypeScript resolves relative imports from the location of the current file, looking for a matching file with the specified path. When the file doesn't exist at that path, TypeScript raises this error.
How do I fix "TS2307"?
This error occurs when TypeScript cannot resolve a relative module import path, usually due to incorrect file paths, missing file extensions, case sensitivity issues, or misconfigured tsconfig.json. The fix involves verifying the import path, checking the actual file location, and configuring module resolution settings correctly.
What causes "TS2307"?
File path in the import statement doesn't match the actual file location File extension (.ts, .tsx, .js, .json) is missing from the import Filename has different casing (Windows is case-insensitive, Linux is case-sensitive)
Is the "TS2307" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading