tsm: TypeScript Module Loader
tsm is a TypeScript Module Loader for Node.js, currently at version 2.3.0, enabling seamless execution of TypeScript and modern JavaScript files directly within Node.js environments without a separate compilation step. It leverages `esbuild` for high-performance transformations, allowing developers to run `.ts`, `.tsx`, `.mts`, and `.cts` files out-of-the-box. The package is actively maintained, with recent releases addressing compatibility with newer Node.js versions and `esbuild` updates, indicating a responsive release cadence. Its key differentiators include comprehensive support for multiple Node.js execution paradigms: direct CLI invocation (`tsm script.ts`), the `--require` hook for CommonJS environments, and the experimental `--loader` hook for ECMAScript Modules. tsm also handles complex interop scenarios, such as requiring ESM `.js` files, and supports modern TypeScript features like the `satisfies` operator, making it a robust solution for developing Node.js applications with TypeScript by simplifying the developer experience.
Common errors
-
Error [ERR_REQUIRE_ESM]: require() of ES Module ... not supported.
cause Attempting to `require()` a JavaScript file that contains ESM syntax (`import`/`export`) in a CommonJS context without `tsm`'s specific handling, or using an older `tsm` version.fixEnsure `tsm` is installed and active (either via `tsm` CLI or `node --require tsm`). Upgrade `tsm` to `v2.1.1` or newer, which addresses this interop issue. -
(node:...) ExperimentalWarning: The ESM loader API is experimental and subject to change.
cause This warning is issued by Node.js itself, indicating that the `--loader` hook API, which `tsm` utilizes for ESM support, is still experimental and not stable.fixThis is an expected warning when using `tsm` with `node --loader`. It indicates the underlying Node.js API is unstable. Ensure `tsm` is always up-to-date with your Node.js version to mitigate potential breaking changes in the loader API. -
TypeError: Loader hook of type 'resolve' must not return 'undefined'
cause Node.js `v18.6.0` and later versions require the `resolve` hook in ESM loaders to explicitly return `shortCircuit: true` for certain paths or it will throw this error. Older `tsm` versions do not include this.fixUpgrade `tsm` to `v2.2.2` or newer, which includes the necessary `shortCircuit: true` handling for Node.js `>=18.6.0`.
Warnings
- breaking Node.js ESM loader hooks (`--loader`) are marked `Stability 1: Experimental` and have undergone multiple breaking API changes across Node.js versions.
- breaking Node.js v18.6.0 introduced a breaking change requiring `shortCircuit: true` in ESM loader `resolve` hook return values. `tsm` versions prior to `2.2.2` will fail on Node.js v18.6.0+.
- breaking Node.js v16.12.0 updated the ESM loader API (e.g., `resolve` hook signature). `tsm` versions prior to `2.1.3` may not function correctly with Node.js `>=16.12.0` when using `--loader`.
- gotcha Using `require()` for JavaScript files containing ESM syntax (`import`/`export`) will throw `ERR_REQUIRE_ESM` errors in Node.js. `tsm` provides a fix for this, but it's a common Node.js interop challenge.
- gotcha `tsm` relies on `esbuild` for its core transpilation. Major `esbuild` updates (e.g., v0.14.x in `tsm v2.2.0`, v0.15.x in `tsm v2.3.0`) can introduce subtle behavioral changes, new feature support (like `satisfies` operator), or new limitations.
Install
-
npm install tsm -
yarn add tsm -
pnpm add tsm
Imports
- tsm CLI
node my-script.ts
tsm my-script.ts
- Node.js --require hook
import 'tsm'
node --require tsm my-script.tsx
- Node.js --loader hook
node --experimental-loader tsm my-module.jsx
node --loader tsm my-module.jsx
Quickstart
// src/server.ts
import { createServer } from 'http';
const PORT = process.env.PORT ? parseInt(process.env.PORT, 10) : 3000;
createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(`Hello from tsm-powered Node.js server!\nRequest Path: ${req.url}\n`);
}).listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}/`);
console.log('Try visiting /test or any other path.');
});
// To run this server:
// 1. Install tsm: npm install --save-dev tsm
// 2. Add a script to your package.json: "start": "tsm src/server.ts"
// 3. Run: npm start
// Alternatively, run directly: npx tsm src/server.ts