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.
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.
# 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.tsAlign tsconfig and package type
- Ensure tsconfig
module/moduleResolutionmatch the package"type". - Use
.tsfor ESM with the ESM loader, or compile to CJS for a CJS project. - Pin ts-node and Node versions so loader behavior is stable.
How to prevent it
- Register
ts-node/esmin ESM projects. - Keep tsconfig module settings aligned with package
"type". - Consider tsx for simpler TS execution.