How to fix 'esModuleInterop' and 'allowSyntheticDefaultImports' require module resolution in TypeScript

TypeScriptBEGINNERMEDIUMUpdated Dec 8, 2025ยท 146 views

This TypeScript configuration error occurs when esModuleInterop or allowSyntheticDefaultImports are enabled without specifying a moduleResolution strategy. The fix is to add moduleResolution to your tsconfig.json, typically set to 'node', 'node16', or 'bundler' depending on your build environment.

Quick fix

Fixes 'esModuleInterop' and 'allowSyntheticDefaultImports' require module resolution

{
  "compilerOptions": {
    "esModuleInterop": true,
    "moduleResolution": "node",
    "module": "commonjs"
  }
}
  1. Add moduleResolution to tsconfig.json
  2. Verify module and moduleResolution are compatible
  3. Use a recommended tsconfig base
  4. Restart TypeScript server in IDE
typescript โ€” error
{
"compilerOptions": {
"esModuleInterop": true,
"moduleResolution": "node",
"module": "commonjs"
}
}
'esModuleInterop' and 'allowSyntheticDefaultImports' require module resolution

What this error means

This error appears when you enable the esModuleInterop or allowSyntheticDefaultImports compiler options in tsconfig.json without also specifying a moduleResolution strategy. These interoperability options control how TypeScript handles imports between CommonJS and ES modules, but they require TypeScript to know how to resolve module paths. The esModuleInterop option enables better compatibility between CommonJS modules (require/module.exports) and ES modules (import/export syntax), emitting helper code to make default imports work correctly with CommonJS modules. The allowSyntheticDefaultImports option allows you to use default import syntax for modules that don't have a default export, but only affects type checking without changing emitted code. Since both options fundamentally change how TypeScript interprets imports, the compiler requires an explicit moduleResolution strategy to determine where to find modules and what format they use. Without this setting, TypeScript cannot properly analyze module dependencies or emit correct interop code.

Typical symptoms

  • Compiler error stating esModuleInterop requires module resolution
  • Configuration fails when enabling allowSyntheticDefaultImports
  • TypeScript build fails immediately after adding esModuleInterop: true
  • Error appears in tsconfig.json validation in IDE
  • Compiler refuses to start with invalid configuration
  • Similar error for both esModuleInterop and allowSyntheticDefaultImports settings

Common causes

  1. Setting esModuleInterop: true without moduleResolution in tsconfig.json
  2. Enabling allowSyntheticDefaultImports without specifying moduleResolution
  3. Using an incomplete or minimal tsconfig.json from a template
  4. Migrating from older TypeScript version where this wasn't enforced
  5. Copying configuration snippet that omits required moduleResolution setting
  6. Setting module option without corresponding moduleResolution strategy

How to fix "'esModuleInterop' and 'allowSyntheticDefaultImports' require module resolution"

1Add moduleResolution to tsconfig.json

The most common fix is to add a moduleResolution setting that matches your environment. For Node.js projects:

json
{
  "compilerOptions": {
    "esModuleInterop": true,
    "moduleResolution": "node",
    "module": "commonjs"
  }
}

For modern Node.js (v16+) using ES modules:

json
{
  "compilerOptions": {
    "esModuleInterop": true,
    "moduleResolution": "node16",
    "module": "node16"
  }
}

For projects using bundlers (webpack, Vite, esbuild):

json
{
  "compilerOptions": {
    "esModuleInterop": true,
    "moduleResolution": "bundler",
    "module": "esnext"
  }
}

After adding moduleResolution, run the TypeScript compiler:

bash
npx tsc --noEmit
# or
npm run build

The error should disappear, and TypeScript will properly resolve your imports.

2Verify module and moduleResolution are compatible

Ensure your module and moduleResolution settings work together. Here are recommended combinations:

For CommonJS (traditional Node.js):

json
{
  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "node",
    "esModuleInterop": true
  }
}

For ES Modules with Node.js:

json
{
  "compilerOptions": {
    "module": "node16",
    "moduleResolution": "node16",
    "esModuleInterop": true  // Implied as true with node16
  }
}

For bundled frontend apps:

json
{
  "compilerOptions": {
    "module": "esnext",
    "moduleResolution": "bundler",
    "esModuleInterop": true
  }
}

Note that with node16, nodenext, and bundler module resolution, esModuleInterop defaults to true and doesn't need to be explicitly set.

3Use a recommended tsconfig base

To avoid configuration errors, use official TypeScript base configs:

bash
# Install base configs
npm install --save-dev @tsconfig/node18
# or
npm install --save-dev @tsconfig/recommended

Then extend it in your tsconfig.json:

json
{
  "extends": "@tsconfig/node18/tsconfig.json",
  "compilerOptions": {
    // Your overrides here
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

Available bases:
- @tsconfig/node18 - Node.js 18 LTS
- @tsconfig/node20 - Node.js 20 LTS
- @tsconfig/recommended - General purpose
- @tsconfig/next - Next.js projects
- @tsconfig/react-native - React Native
- @tsconfig/vite-react - Vite + React

These bases include proper moduleResolution settings by default.

4Restart TypeScript server in IDE

After updating tsconfig.json, restart the TypeScript language server to apply changes:

VS Code:

Press Cmd/Ctrl + Shift + P, then select "TypeScript: Restart TS Server"

Or use the command palette shortcut:

bash
> TypeScript: Restart TS Server

WebStorm/IntelliJ:

File > Invalidate Caches > select "Clear file system cache and Local History" > Invalidate and Restart

Command line:

bash
# Kill any running TypeScript processes
pkill -f tsc
pkill -f tsserver

# Rebuild from scratch
rm -rf dist
npx tsc

This ensures your IDE picks up the new configuration immediately.

5Remove allowSyntheticDefaultImports if not needed

If you're only using esModuleInterop, you can remove allowSyntheticDefaultImports entirely:

json
{
  "compilerOptions": {
    // esModuleInterop implies allowSyntheticDefaultImports
    "esModuleInterop": true,
    "moduleResolution": "node"
    // No need for allowSyntheticDefaultImports
  }
}

The esModuleInterop option automatically enables allowSyntheticDefaultImports, so setting both is redundant.

If you're not using esModuleInterop and only want type checking without runtime helpers:

json
{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "moduleResolution": "node",
    // esModuleInterop: false (default)
  }
}

However, for most projects, using esModuleInterop: true is recommended as it provides both type checking and correct runtime behavior.

Advanced notes

### Understanding esModuleInterop vs allowSyntheticDefaultImports

These two options solve different but related problems:

allowSyntheticDefaultImports (type checking only):

This option tells TypeScript to allow default imports from modules that don't have a default export. It only affects TypeScript's type checker - no JavaScript code is changed:

typescript
// CommonJS module (lodash)
// module.exports = { map, filter, reduce, ... }

// With allowSyntheticDefaultImports: true
import _ from "lodash";  // Type checking allows this
// But emits: const _ = require("lodash"); // Won't work at runtime!

esModuleInterop (runtime code generation):

This option emits additional helper code to make default imports work correctly with CommonJS modules:

typescript
import _ from "lodash";

// Emits:
var __importDefault = (this && this.__importDefault) || function (mod) {
  return (mod && mod.__esModule) ? mod : { "default": mod };
};
const lodash_1 = __importDefault(require("lodash"));
// Now lodash_1.default works correctly

Setting esModuleInterop: true automatically enables allowSyntheticDefaultImports and generates the runtime helpers.

### Module Resolution Strategies Explained

TypeScript supports several moduleResolution strategies:

classic - Legacy strategy, rarely used today. Doesn't support node_modules.

node - Traditional Node.js CommonJS resolution:
- Looks in node_modules
- Supports package.json "main" field
- Default for module: "commonjs"

node16/nodenext - Modern Node.js with ES module support:
- Respects package.json "type": "module"
- Supports "exports" field
- Requires .js extensions in relative imports
- Auto-enables esModuleInterop

bundler - For Vite, webpack, esbuild:
- Supports package.json "imports" and "exports"
- Never requires file extensions
- Assumes bundler handles module resolution
- Auto-enables esModuleInterop

### When to Use Each Configuration

Building a library for npm:

json
{
  "compilerOptions": {
    "module": "esnext",
    "moduleResolution": "bundler",
    "esModuleInterop": true,
    "declaration": true
  }
}

Node.js backend (CommonJS):

json
{
  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "target": "ES2020"
  }
}

Node.js backend (ES modules):

json
{
  "compilerOptions": {
    "module": "node16",
    "moduleResolution": "node16",
    "target": "ES2022"
  }
}

Note: With node16, you must use .js extensions in relative imports even though source files are .ts:

typescript
// WRONG
import { foo } from "./utils/helper";

// CORRECT
import { foo } from "./utils/helper.js";

React frontend (bundled):

json
{
  "compilerOptions": {
    "module": "esnext",
    "moduleResolution": "bundler",
    "jsx": "react-jsx",
    "esModuleInterop": true
  }
}

### Why This Requirement Exists

In older TypeScript versions, you could set esModuleInterop without moduleResolution, leading to ambiguous behavior. Modern TypeScript enforces that these interop options must be paired with an explicit resolution strategy because:

1. The interop code generated depends on how modules are resolved
2. Different resolution strategies have different rules (e.g., file extensions)
3. Type checking behavior differs based on resolution mode
4. It prevents misconfigured projects that compile but fail at runtime

### Checking Your Configuration

Verify your current configuration:

bash
npx tsc --showConfig

This outputs the final resolved configuration including defaults, helping you see exactly what TypeScript is using.

Frequently asked questions

What does "'esModuleInterop' and 'allowSyntheticDefaultImports' require module re" mean?
json without also specifying a moduleResolution strategy. These interoperability options control how TypeScript handles imports between CommonJS and ES modules, but they require TypeScript to know how to resolve module paths. exports) and ES modules (import/export syntax), emitting helper code to make default imports work correctly with CommonJS modules.
How do I fix "'esModuleInterop' and 'allowSyntheticDefaultImports' require module re"?
This TypeScript configuration error occurs when esModuleInterop or allowSyntheticDefaultImports are enabled without specifying a moduleResolution strategy. The fix is to add moduleResolution to your tsconfig.json, typically set to 'node', 'node16', or 'bundler' depending on your build environment.
What causes "'esModuleInterop' and 'allowSyntheticDefaultImports' require module re"?
Setting esModuleInterop: true without moduleResolution in tsconfig.json Enabling allowSyntheticDefaultImports without specifying moduleResolution Using an incomplete or minimal tsconfig.json from a template
Is the "'esModuleInterop' and 'allowSyntheticDefaultImports' require module re" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading