jestjs/jest · error · Error

Jest: Failed to load ESM at ${filePath} - did you use a defa

Error message

Jest: Failed to load ESM at ${filePath} - did you use a default export?

What it means

Thrown by `importModule` (requireOrImportModule.ts:28-32) when an ESM module (`.mjs`/`.mts`, or a `.js` that triggered `ERR_REQUIRE_ESM`) is dynamically imported, `applyInteropRequireDefault` is true, but the resulting namespace has no `default` export. Jest's interop layer expects a default export to hand back to callers that requested the CJS-style default.

Source

Thrown at packages/jest-util/src/requireOrImportModule.ts:29

async function importModule(
  filePath: string,
  applyInteropRequireDefault: boolean,
) {
  try {
    const moduleUrl = pathToFileURL(filePath);

    // node `import()` supports URL, but TypeScript doesn't know that
    const importedModule = await import(
      /* webpackIgnore: true */ moduleUrl.href
    );

    if (!applyInteropRequireDefault) {
      return importedModule;
    }

    if (!importedModule.default) {
      throw new Error(
        `Jest: Failed to load ESM at ${filePath} - did you use a default export?`,
      );
    }

    return importedModule.default;
  } catch (error: any) {
    if (error.message === 'Not supported') {
      throw new Error(
        `Jest: Your version of Node does not support dynamic import - please enable it or use a .cjs file extension for file ${filePath}`,
      );
    }
    throw error;
  }
}

export default async function requireOrImportModule<T>(
  filePath: string,
  applyInteropRequireDefault = true,

View on GitHub (pinned to f49721c78e)

Solutions

  1. Add `export default` to the ESM module: `export default { ... }` instead of `export const ...`.
  2. If loading through an API that passes `applyInteropRequireDefault=false`, named exports are returned as the namespace - use that variant when you control the call site.
  3. For Jest config specifically, use the documented ESM form `export default async () => ({...})`.

Example fix

// before: jest.config.mjs
export const config = { testEnvironment: 'node' };
// after
export default { testEnvironment: 'node' };
Defensive patterns

Strategy: type-guard

Validate before calling

// Check the module namespace before relying on .default
const mod = await import(pathToFileURL(filePath).href);
if (!('default' in mod)) throw new Error(`${filePath} needs a default export`);

Type guard

const hasDefaultExport = (m: any): boolean =>
  m != null && 'default' in m && m.default !== undefined;

Prevention

When it happens

Trigger: Loading a module via `requireOrImportModule(path)` (used for config files, snapshot resolvers, transformers, custom runners) where the target module is ESM with only named exports and no `default`.

Common situations: An ESM config file (`jest.config.mjs`) that does `export const config = {...}` instead of `export default {...}`; a custom snapshot resolver / transformer written as ESM named exports; switching a CJS config (which had `module.exports =`) to ESM and forgetting to switch to `export default`.

Related errors


AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03). Data as JSON: /data/errors/da51638b9d9b8380.json. Report an issue: GitHub.