This TypeScript configuration error occurs when an invalid value is set for the moduleResolution compiler option in tsconfig.json. The fix involves correcting the moduleResolution value to one of the valid options: 'node', 'node16', 'nodenext', 'classic', or 'bundler'.
The "'moduleResolution' should be 'node' or 'classic'" error appears when TypeScript encounters an invalid value for the `moduleResolution` compiler option in your tsconfig.json file. This option controls how TypeScript resolves module imports and must be set to one of the officially supported values. Module resolution is a critical part of TypeScript's compilation process. It determines how the compiler finds the files referenced in import statements. When you specify an unsupported value, TypeScript cannot proceed with compilation because it doesn't know how to resolve your module imports. Historically, TypeScript supported only 'node' and 'classic' resolution strategies. Modern versions have added 'node16', 'nodenext', and 'bundler' options to support newer JavaScript module systems and bundlers. The error message mentioning only 'node' or 'classic' can be misleading if you're using a newer TypeScript version that supports additional options.
First, check your tsconfig.json file to see what value is set for moduleResolution:
// tsconfig.json
{
"compilerOptions": {
// Look for this line:
"moduleResolution": "node", // Should be one of: node, node16, nodenext, classic, bundler
// Other options...
}
}Common incorrect values to watch for:
- "moduleResolution": "Node" (capital N - should be lowercase)
- "moduleResolution": "nodes" (typo - missing 'e')
- "moduleResolution": "nod" (incomplete)
- "moduleResolution": "esnext" (this is for 'module', not 'moduleResolution')
- "moduleResolution": "commonjs" (this is for 'module', not 'moduleResolution')
If you don't see moduleResolution in your tsconfig.json, TypeScript uses a default value based on your 'module' setting.
Select the appropriate moduleResolution based on your project type:
{
"compilerOptions": {
// For Node.js projects (CommonJS):
"moduleResolution": "node",
"module": "commonjs",
// For modern Node.js (ES modules with "type": "module" in package.json):
"moduleResolution": "node16", // or "nodenext"
"module": "node16", // or "nodenext"
// For bundlers like webpack, Vite, esbuild:
"moduleResolution": "bundler",
"module": "esnext",
// Legacy TypeScript resolution (rarely used):
"moduleResolution": "classic",
"module": "amd" // or "system", "umd"
}
}Quick reference:
- Node.js CommonJS projects: Use "moduleResolution": "node"
- Node.js ES modules: Use "moduleResolution": "node16" or "nodenext"
- Frontend with bundler: Use "moduleResolution": "bundler"
- Legacy/rare cases: Use "moduleResolution": "classic"
Some moduleResolution values require newer TypeScript versions:
# Check your current TypeScript version
npx tsc --version
# Update TypeScript globally
npm install -g typescript@latest
# Or update in your project
npm install --save-dev typescript@latest
# Verify the update
npm list typescriptVersion requirements:
- "node16" and "nodenext": TypeScript 4.7+
- "bundler": TypeScript 5.0+
- "node" and "classic": All TypeScript versions
If you need to support older TypeScript versions but want modern module resolution, consider:
1. Upgrading TypeScript (recommended)
2. Using "moduleResolution": "node" with appropriate module settings
3. Configuring your bundler to handle module resolution
Ensure your tsconfig.json has valid JSON syntax:
// WRONG - missing quotes
{
"compilerOptions": {
moduleResolution: node // Should be "moduleResolution": "node"
}
}
// WRONG - extra comma
{
"compilerOptions": {
"moduleResolution": "node", // Trailing comma in JSON
}
}
// CORRECT
{
"compilerOptions": {
"moduleResolution": "node"
}
}Check for configuration inheritance:
If you extend another tsconfig.json file:
// tsconfig.base.json
{
"compilerOptions": {
"moduleResolution": "invalid-value" // This causes the error
}
}
// tsconfig.json
{
"extends": "./tsconfig.base.json", // Inherits the invalid value
"compilerOptions": {
// Override the invalid value
"moduleResolution": "node"
}
}Use a JSON validator to check syntax:
# Using node
node -e "console.log(JSON.parse(require('fs').readFileSync('tsconfig.json', 'utf8')))"
# Using jq (if installed)
jq . tsconfig.jsonAfter fixing the moduleResolution value, test your configuration:
# Run TypeScript compiler to check for errors
npx tsc --noEmit
# If using a build script
npm run build
# Check specific files
npx tsc src/index.ts --noEmitVerify module resolution is working:
Create a test file to ensure imports resolve correctly:
// test-import.ts
import * as path from "path"; // Node.js built-in
import React from "react"; // External package
import { myUtil } from "./utils"; // Local file
console.log("Module resolution is working!");Compile it:
npx tsc test-import.ts --noEmitIf you still get errors, check:
1. The exact spelling of "moduleResolution" (case-sensitive)
2. That the value is a string, not a number or boolean
3. That there are no hidden characters or encoding issues
Different frameworks have preferred moduleResolution settings:
Next.js:
{
"compilerOptions": {
"moduleResolution": "bundler",
"module": "esnext",
"target": "es5"
}
}React with Create React App:
{
"compilerOptions": {
"moduleResolution": "node",
"module": "esnext",
"target": "es5"
}
}Angular:
{
"compilerOptions": {
"moduleResolution": "node",
"module": "es2020",
"target": "es2020"
}
}NestJS:
{
"compilerOptions": {
"moduleResolution": "node",
"module": "commonjs",
"target": "es2017"
}
}If using a framework template:
Check the framework's documentation or starter template for the recommended tsconfig.json configuration. Many frameworks provide a base tsconfig.json that you should extend rather than modifying directly.
### Historical Context and Error Message
The error message "'moduleResolution' should be 'node' or 'classic'" originates from TypeScript's early versions when only these two options existed. Despite newer options being added, the error message hasn't been updated in all cases. This can be confusing when you're trying to use 'node16', 'nodenext', or 'bundler'.
### moduleResolution vs module
It's important to distinguish between moduleResolution and module:
- `module`: Determines the module system for the output JavaScript (commonjs, es2015, esnext, etc.)
- `moduleResolution`: Determines how TypeScript finds the source modules during compilation
Common mismatches:
// WRONG - moduleResolution doesn't match module
{
"module": "esnext",
"moduleResolution": "node" // Should be "bundler" for esnext with bundlers
}
// CORRECT - aligned settings
{
"module": "esnext",
"moduleResolution": "bundler" // For bundlers like webpack, Vite
}### TypeScript Version Compatibility Matrix
| moduleResolution | TypeScript | Use Case |
|-----------------|------------|----------|
| classic | 1.0+ | Legacy AMD/System.js projects |
| node | 1.0+ | Node.js CommonJS (default for commonjs module) |
| node16 | 4.7+ | Node.js ES modules (package.json "type": "module") |
| nodenext | 4.7+ | Same as node16, future-proof naming |
| bundler | 5.0+ | Modern bundlers (webpack, Vite, esbuild, etc.) |
### Debugging Module Resolution
To see how TypeScript resolves modules:
# Trace module resolution for a specific file
npx tsc --traceResolution src/index.ts
# See all resolution attempts
npx tsc --traceResolution | grep "======== Resolving module"
# Check which tsconfig.json is being used
npx tsc --showConfig### Common Pitfalls
1. Framework-specific configurations: Some frameworks (like Angular) have their own compilation pipeline and may ignore certain tsconfig.json settings.
2. Monorepos: In monorepos, each package might need its own tsconfig.json with appropriate moduleResolution settings based on its role (library vs application).
3. Mixed module systems: If you have both CommonJS and ES modules in your project, you may need to use "moduleResolution": "node16" with proper package.json configuration.
4. Bundler plugins: Some bundlers have plugins that affect TypeScript compilation (like @vitejs/plugin-react for Vite). Ensure these are configured correctly.
### Migration Strategies
When migrating from older TypeScript versions or module systems:
1. From classic to node: Update imports to use Node.js resolution rules (no .ts extensions, index file resolution).
2. From node to node16: Add .js extensions to relative imports in TypeScript source files.
3. To bundler: Ensure your bundler is configured to match TypeScript's resolution strategy.
### References
- [TypeScript Module Resolution Documentation](https://www.typescriptlang.org/docs/handbook/module-resolution.html)
- [TSConfig moduleResolution Reference](https://www.typescriptlang.org/tsconfig#moduleResolution)
- [Node.js Module Resolution](https://nodejs.org/api/esm.html#resolution-algorithm)
- [Bundler Module Resolution](https://www.typescriptlang.org/docs/handbook/modules/reference.html#bundler)
Function expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript