Skip to content
Latchkey

Node tsx/ts-node Runtime Resolution Error in CI - Fix the TypeScript Loader

tsx and ts-node run TypeScript through a custom loader. Resolution errors appear when the loader, the module setting, and import extensions disagree.

What this error means

Running TS directly with tsx or ts-node fails in CI with a resolution error (cannot find module or unknown extension) even though tsc compiles the project fine.

node
TypeError [ERR_MODULE_NOT_FOUND]: Cannot find module
'/home/runner/work/app/app/src/utils' imported from
/home/runner/work/app/app/src/index.ts
    at finalizeResolution (node:internal/modules/esm/resolve:264:11)

Common causes

Extensionless imports under ESM resolution

In ESM mode the loader does not append .ts/.js, so a bare relative import fails to resolve.

A loader and tsconfig module mismatch

The ts-node/tsx loader expects one module system while tsconfig targets another, so resolution diverges from tsc.

How to fix it

Use tsx, which handles extensions

  1. Run the TypeScript entry through tsx in CI.
  2. Use the same command locally.
GitHub Actions
- run: npx tsx src/index.ts

Align ts-node ESM settings

  1. Enable ts-node ESM support and allow .ts extensions in imports.
  2. Match the tsconfig module setting to the loader mode.
tsconfig.json
// tsconfig.json
"ts-node": { "esm": true, "experimentalSpecifierResolution": "node" }

How to prevent it

  • Pick one TypeScript runner and keep its loader, the tsconfig module setting, and import-extension style consistent between local dev and CI.

Frequently asked questions

What causes ""tsx/ts-node could not resolve module""?
In ESM mode the loader does not append .ts/.js, so a bare relative import fails to resolve.
How do I fix "tsx/ts-node could not resolve module"?
Use tsx, which handles extensions

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card