Skip to content
Latchkey

ts-node "ERR_UNKNOWN_FILE_EXTENSION .ts" - Fix ESM Loader Setup in CI

Under ESM, Node only knows how to load known extensions. Running a .ts file as ESM without registering ts-node’s ESM loader makes Node throw ERR_UNKNOWN_FILE_EXTENSION because nothing handles .ts.

What this error means

Running TypeScript with ts-node in an ESM project fails with ERR_UNKNOWN_FILE_EXTENSION: Unknown file extension ".ts". It happens when "type": "module" is set but ts-node is invoked without its ESM loader.

ts-node output
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"
for /app/src/index.ts
    at Object.getFileProtocolModuleFormat (node:internal/modules/esm/...)

Common causes

ESM project without ts-node’s ESM loader

With "type": "module", Node uses the ESM resolver, which has no handler for .ts unless ts-node’s ESM loader is registered.

Mismatched tsconfig module settings

A tsconfig emitting CommonJS while the package is ESM (or vice versa) confuses the loader about how to interpret the file.

How to fix it

Register the ts-node ESM loader

Use ts-node’s ESM entrypoint so the loader handles .ts under ESM.

Terminal
# ESM project
node --loader ts-node/esm src/index.ts
# or the modern form
node --import ts-node/register/esm src/index.ts
# or use the wrapper
npx ts-node --esm src/index.ts

Align tsconfig and package type

  1. Ensure tsconfig module/moduleResolution match the package "type".
  2. Use .ts for ESM with the ESM loader, or compile to CJS for a CJS project.
  3. Pin ts-node and Node versions so loader behavior is stable.

How to prevent it

  • Register ts-node/esm in ESM projects.
  • Keep tsconfig module settings aligned with package "type".
  • Consider tsx for simpler TS execution.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →