{"record":{"id":"f6ac72c35f368d52","repo":"jestjs/jest","slug":"jest-config-mts-requires-native-typescript-support","errorCode":null,"errorMessage":"jest.config.mts requires native TypeScript support. Ensure you are using Node.js 22.18+ or 23.6+.","messagePattern":"jest\\.config\\.mts requires native TypeScript support\\. Ensure you are using Node\\.js 22\\.18\\+ or 23\\.6\\+\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/jest-config/src/readConfigFileAndSetRootDir.ts","lineNumber":55,"sourceCode":"    configPath.endsWith(JEST_CONFIG_EXT_TS) ||\n    configPath.endsWith(JEST_CONFIG_EXT_MTS) ||\n    configPath.endsWith(JEST_CONFIG_EXT_CTS);\n  const isMTS = configPath.endsWith(JEST_CONFIG_EXT_MTS);\n  const isJSON = configPath.endsWith(JEST_CONFIG_EXT_JSON);\n  let configObject;\n\n  try {\n    if (isTS) {\n      // .mts is always ESM, so attempt import-based loading first.\n      // @ts-expect-error: Type assertion can be removed once @types/node is updated to 23 https://nodejs.org/api/process.html#processfeaturestypescript\n      if (isMTS || process.features.typescript) {\n        try {\n          // Try native node TypeScript support first.\n          configObject = await requireOrImportModule<any>(configPath);\n        } catch (requireOrImportModuleError) {\n          if (isMTS) {\n            // .mts is always ESM and cannot be loaded via require()/ts-node.\n            throw new Error(\n              'jest.config.mts requires native TypeScript support. Ensure you are using Node.js 22.18+ or 23.6+.',\n              {cause: requireOrImportModuleError},\n            );\n          }\n          if (!(requireOrImportModuleError instanceof SyntaxError)) {\n            if (!hasTsLoaderExplicitlyConfigured(configPath)) {\n              throw requireOrImportModuleError;\n            }\n          }\n          try {\n            // There are various reasons of failed loadout of Jest config in Typescript:\n            // 1. User has specified a TypeScript loader in the docblock and\n            // desire non-native compilation (https://github.com/jestjs/jest/issues/15837)\n            // 2. Likely ESM in a file interpreted as CJS, which means it needs to be\n            // compiled. We ignore the error and try to load it with a loader.\n            configObject = await loadTSConfigFile(configPath);\n          } catch (loadTSConfigFileError) {\n            // If we still encounter an error, we throw both messages combined.","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/jestjs/jest/blob/8e6d128e4a278059ecddecaa97400b04c8ae5fd9/packages/jest-config/src/readConfigFileAndSetRootDir.ts#L37-L73","documentation":"Thrown when a jest.config.mts file cannot be loaded. Per the project's CLAUDE.md, .mts is always ESM and cannot be loaded via require() or ts-node. The loader first attempts native Node TypeScript support (process.features.typescript, available in Node 22.18+ / 23.6+); on any failure for .mts it throws this hard error with no fallback.","triggerScenarios":"Running Jest with a jest.config.mts on an older Node version that lacks native TypeScript stripping (pre-22.18 or pre-23.6), or on a Node build with TypeScript support disabled.","commonSituations":"Teams adopting .mts config files without upgrading Node; CI environments pinned to older LTS Node versions; local developers on nvm with an older default.","solutions":["Upgrade Node.js to 22.18+ or 23.6+ where native TypeScript support is enabled","If upgrade is blocked, rename the config to jest.config.ts so the ts-node/esbuild-register fallback path can be used","Add an @jest-config-loader docblock pragma only if using .ts/.cts (it has no effect for .mts)","Verify with node --experimental-strip-types that your Node build supports TS"],"exampleFix":"// before: jest.config.mts on Node 20\nexport default defineConfig({ /* ... */ });\n\n// after option A: upgrade Node to 22.18+\n// after option B: rename to jest.config.ts and add docblock\n/**\n * @jest-config-loader ts-node\n */\nimport type {Config} from 'jest';\nconst config: Config = { /* ... */ };\nexport default config;","handlingStrategy":"validation","validationCode":"import * as semver from 'semver';\nfunction nodeSupportsNativeTS(): boolean {\n  const major = Number(process.versions.node.split('.').map(Number)[0]);\n  const minor = Number(process.versions.node.split('.')[1]);\n  // 22.18+ or 23.6+\n  return semver.gte(process.versions.node, '22.18.0') || semver.gte(process.versions.node, '23.6.0');\n}\nif (fs.existsSync('jest.config.mts') && !nodeSupportsNativeTS()) {\n  throw new Error('jest.config.mts requires Node 22.18+ or 23.6+');\n}","typeGuard":"function nodeSupportsMtsConfig(): boolean {\n  // @ts-expect-error process.features.typescript is typed in newer @types/node\n  return Boolean(process.features?.typescript);\n}","tryCatchPattern":null,"preventionTips":["Pin your project's engines.node to >=22.18 in package.json","Add a CI step that fails if Node version is below the threshold when a .mts config exists","Use a .nvmrc or .node-version file committed to the repo"],"tags":["typescript","config","node-version","esm","loader"],"backgroundTag":null,"analyzedSha":"8e6d128e4a278059ecddecaa97400b04c8ae5fd9","analyzedAt":"2026-08-10T18:11:27.960Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}