Compilation and execution answer different questions
TypeScript can understand a source import while the emitted JavaScript still fails to load in Node.js. The compiler's resolution model, package metadata and runtime's module system must agree. A development runner or bundler can hide differences that become visible when production executes emitted files directly.
This guide concerns ECMAScript modules and CommonJS boundaries. It is separate from project-reference build order: declarations may exist and compilation may complete while runtime import resolution remains wrong. Establish how the application is actually launched before changing module settings.
Setup: capture the whole module contract
Record the Node.js and TypeScript versions, package.json type and exports fields, compiler module settings and emitted file extensions. Identify whether production runs a bundle, a loader or plain Node.js. Use the lockfile and local compiler; a globally installed development tool can produce a different result.
The TypeScript module reference describes Node-oriented modes that model Node's module behavior. Choose settings appropriate to the supported runtime and compiler release. Do not assume that a bundler-oriented resolution mode makes plain Node understand aliases or extension rules that only the bundler implements.
Illustrative incident: development works, dist fails
An illustrative API runs through a convenient development command. CI builds successfully, but starting the emitted entry file produces a module-not-found error. Inspection shows a source alias survived into a runtime import without a runtime mapping. This is a teaching scenario, not a report about a particular customer codebase.
Reproduce from a clean release artifact using the exact production start command. Preserve the first error and the emitted importing file. Looking only at the TypeScript source can miss the path and extension that Node actually receives.
Troubleshooting: compare the emitted edge
| Symptom | Evidence | Investigation |
|---|---|---|
| Alias import fails only in production | Emitted specifier and runtime loader | Who resolves that alias after compilation? |
| Module syntax is rejected | File extension and package type boundary | Is Node interpreting the file in the intended mode? |
| Package subpath cannot be loaded | Package exports and installed version | Is that entry point actually published? |
| One machine succeeds with old files | Clean output directory and artifact listing | Is a stale emitted file hiding the mismatch? |
Do not fix an error by randomly alternating module modes until the compiler becomes quiet. Such changes affect interoperability and can move the failure to another import. Trace a concrete importing file and target package first.
Corrective action with one supported launch model
Align the compiler, package metadata and production launcher on a documented module strategy. If a bundler is part of the design, test its actual output. If Node runs emitted files directly, ensure every runtime specifier can be resolved under that model. Treat source-only path aliases as a compile-time convenience unless a verified runtime mechanism implements them.
Review dependencies that expose different entry points for import and require. A type declaration being available does not guarantee identical runtime exports in both modes. Keep the correction small, rebuild from a clean output directory and preserve a known-good artifact for rollback rather than editing generated files on the server.
Verification, release objective and SOP
Execute the production entry point from the packaged artifact without the development runner. Exercise representative dynamic imports and package subpaths, not just startup. Confirm that missing modules fail visibly and that the release does not depend on files left outside the artifact by a previous deployment.
An internal release objective should include successful execution of the supported module graph. Compiler success is one indicator, not the entire objective. A customer-facing SLA concerns the resulting service and needs separate definitions. The SOP should list the launcher, compiler mode, package ownership, clean-build procedure and evidence required for a dependency upgrade. Avoid unsupported claims that one module format is always faster or more secure.
Explore JavaScript and TypeScript development and DevOps automation.
Technical reference
TypeScript module reference, reviewed 19 October 2026. Follow documentation matching the installed product version.