This TypeScript configuration error occurs when you try to use the modern 'esnext' module system with legacy JavaScript targets (ES3 or ES5). The esnext module format requires modern JavaScript features that aren't available in older ECMAScript versions. To fix this, either upgrade your target to ES2015+ or switch to a compatible module system like CommonJS.
The "Option 'module' cannot be set to 'esnext' when 'target' is 'es3' or 'es5'" error appears when there's an incompatibility between your TypeScript compiler settings in tsconfig.json. The `module` option controls how TypeScript generates module code (import/export statements), while the `target` option determines which ECMAScript version your code compiles to. The 'esnext' module system uses modern JavaScript module syntax that requires features only available in ES2015 (ES6) and later. ES3 (1999) and ES5 (2009) are legacy JavaScript versions that don't support: - ES modules (`import`/`export` syntax) - Arrow functions (used in some module transformations) - Modern class syntax - Other ES6+ features that TypeScript's 'esnext' module output may rely on TypeScript prevents this combination because the generated code would be invalid JavaScript for your target environment. You need to either: 1. Upgrade your `target` to ES2015 or later to use modern module systems 2. Change your `module` to a format compatible with ES3/ES5 (like 'commonjs' or 'umd')
First, examine your tsconfig.json file to see the current module and target values:
// tsconfig.json
{
"compilerOptions": {
"module": "esnext", // ← This is the problem
"target": "es5", // ← Incompatible with esnext
// ... other options
}
}Look for these lines in your configuration. The error specifically mentions the combination of 'module: esnext' with 'target: es3' or 'target: es5'.
You can also check from the command line:
# Show effective TypeScript configuration
npx tsc --showConfig
# Or check specific files
cat tsconfig.json | grep -E "(module|target)"The simplest fix is to upgrade your target to a modern ECMAScript version that supports ES modules:
{
"compilerOptions": {
"module": "esnext",
"target": "es2015", // ← Changed from es5 to es2015
"lib": ["es2015", "dom"],
// ... other options
}
}Recommended targets:
- ES2015 (ES6): Minimum for ES module support
- ES2017: Good balance of compatibility and modern features
- ES2020: Modern JavaScript with latest features
- ESNext: Latest ECMAScript features (experimental)
Consider your deployment environment:
- Node.js: Check your Node version compatibility
- Browsers: Use a bundler (webpack, Vite) that transpiles for browser support
- Legacy browsers: You'll need a bundler with polyfills regardless
After updating, test the compilation:
npx tsc --noEmit
# or
npm run buildIf you must target ES3/ES5 (for legacy browser support), change the module system to a compatible format:
{
"compilerOptions": {
"module": "commonjs", // ← Changed from esnext to commonjs
"target": "es5",
// ... other options
}
}Compatible module formats for ES3/ES5:
- commonjs: Node.js-style modules (require/exports)
- umd: Universal Module Definition (works in browsers and Node.js)
- amd: Asynchronous Module Definition (RequireJS)
- system: SystemJS module loader
- none: No module system (global scope)
Most common choice for ES5 targets:
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"lib": ["es5", "dom"],
"esModuleInterop": true, // Important for CommonJS/ES module interop
"allowSyntheticDefaultImports": true
}
}Note: With 'commonjs', you'll use require() syntax in output, but can still write import/export in TypeScript.
If you're using tsconfig inheritance or multiple configuration files, check all relevant files:
// tsconfig.base.json (parent config)
{
"compilerOptions": {
"module": "esnext",
"target": "es2015"
}
}
// tsconfig.json (extends base)
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"target": "es5" // ← Overrides to incompatible value!
}
}Common patterns to check:
1. Extends chains: Follow the inheritance chain
2. Project references: Check referenced project configurations
3. Build tools: Webpack, Vite, etc. may generate tsconfig
4. IDE settings: VS Code workspace settings can affect compilation
To see the final merged configuration:
npx tsc --showConfig > tsconfig.effective.json
cat tsconfig.effective.json | grep -A2 -B2 "module|target"Create a minimal tsconfig.json to isolate the issue:
// tsconfig.minimal.json
{
"compilerOptions": {
"module": "esnext",
"target": "es2015"
},
"include": ["src/**/*"]
}Test with this minimal config:
npx tsc --project tsconfig.minimal.json --noEmitIf this works, gradually add back your other compiler options to find which combination causes the error.
Common problematic options to check:
- moduleResolution: Should match your module system
- lib: Library files for your target
- esModuleInterop: Important for module compatibility
- allowSyntheticDefaultImports: Affects import behavior
Ensure your build tools support your TypeScript configuration:
# Update TypeScript
npm install --save-dev typescript@latest
# Update related tools
npm install --save-dev @types/node ts-node
# For webpack users
npm install --save-dev ts-loader webpack webpack-cli
# For Vite users
npm install --save-dev vite @vitejs/plugin-reactCheck package.json scripts:
{
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"check": "tsc --noEmit"
}
}Run a clean build:
# Clear build artifacts
rm -rf dist build node_modules/.cache
# Reinstall dependencies
npm install
# Test compilation
npm run checkIf using a framework (React, Angular, Vue), check their TypeScript requirements.
### Understanding Module and Target Compatibility
TypeScript's module system transforms your import/export statements into different output formats based on the module setting. The target determines the JavaScript syntax features available.
Compatibility Matrix:
| Module System | ES3/ES5 | ES2015+ | Notes |
|---------------|---------|---------|-------|
| commonjs | ✓ | ✓ | Node.js default, requires bundler for browsers |
| amd | ✓ | ✓ | Async Module Definition (RequireJS) |
| umd | ✓ | ✓ | Universal (works everywhere) |
| system | ✓ | ✓ | SystemJS loader |
| es2015 | ✗ | ✓ | Native ES6 modules |
| es2020 | ✗ | ✓ | ES2020 module features |
| esnext | ✗ | ✓ | Latest proposals |
Why esnext requires ES2015+:
- esnext may use dynamic import() expressions (ES2020)
- May output export * as ns syntax (ES2020)
- Can use top-level await (ES2022)
- Future JavaScript module features
### Migration Strategies
From ES5 + CommonJS to ES2015 + ES Modules:
1. Update target: "es5" → "es2015"
2. Update module: "commonjs" → "esnext"
3. Add lib: ["es2015", "dom"]
4. Test with a bundler (webpack, Rollup)
Legacy Browser Support:
If you need ES5 for IE11 support:
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"downlevelIteration": true,
"lib": ["es5", "dom", "es2015.promise"]
}
}Then use Babel + webpack to transpile CommonJS to browser-compatible code.
### Module Resolution Differences
The moduleResolution option should align with your module:
- module: "commonjs" → moduleResolution: "node"
- module: "esnext" → moduleResolution: "node" (or "bundler" for modern tools)
- module: "es2015" → moduleResolution: "node"
Modern bundlers (Vite, esbuild) work best with:
{
"module": "esnext",
"moduleResolution": "bundler",
"target": "es2020"
}### Checking Your Environment
To see what JavaScript features your target supports:
# Check Node.js version
node --version
# Check browser support via caniuse.com or MDN
# ES modules: https://caniuse.com/es6-module
# Dynamic import: https://caniuse.com/es6-module-dynamic-importFor Node.js projects, match target to your Node version:
- Node 12+: "target": "es2019"
- Node 14+: "target": "es2020"
- Node 16+: "target": "es2021"
### Debugging Configuration Issues
Use TypeScript's verbose output:
npx tsc --extendedDiagnostics
npx tsc --listFiles
npx tsc --traceResolutionThese show exactly how TypeScript interprets your configuration and files.
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