Chapter 22: Build and Run Strategies
Once your project structure is in place, you need a reliable way to turn TypeScript into something Node can execute. Some teams prefer a classic compile step, others run code on the fly during development, and larger projects often adopt fast builders that compress the edit to feedback loop. This chapter explores these approaches so you can pick the style that fits your workflow.
Transpile and run: tsc outDir workflow
This workflow compiles TypeScript files into a dedicated output directory and points Node at the generated JavaScript. It keeps the boundary between source and build products clear, which is helpful for libraries and production deployments. You write code in src, then run tsc to emit into dist or another folder of your choice.
Clean separation of source and output
A split between directories avoids confusion when debugging and removes the risk of shipping TypeScript files by mistake. Most teams use a structure similar to the one below, where src holds the TypeScript and dist receives the compiled output.
my-app/
src/…
dist/…
tsconfig.json
Configuring the compiler
Set rootDir and outDir so that TypeScript mirrors your folder structure and emits files consistently. This also helps tools like nodemon or pm2 watch the correct location.
{
"compilerOptions": {
"rootDir": "src",
"outDir": "dist",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"sourceMap": true
}
}
npm publish predictable.
On the fly execution with tsx or ts-node
Sometimes you want instant execution without a manual build step. Tools like tsx and ts-node execute TypeScript directly by compiling each file just before running it. This keeps iteration fast and cuts down on the number of moving parts during development.
Using tsx for ESM friendly projects
tsx handles modern ESM resolution rules and supports speedy startup. It respects your tsconfig.json and keeps imports stable, which suits apps that lean on Node’s current resolution model.
npx tsx src/index.ts
ts-node for classic environments
ts-node hooks into Node’s loader chain and works well for CommonJS or mixed projects. While not as fast as dedicated builders, it is simple and dependable for small apps or command line tools.
npx ts-node src/index.ts
Fast builders: esbuild and swc
For large codebases, build speed becomes part of developer happiness. Builders like esbuild and swc compile TypeScript extremely quickly and can bundle code when needed. They skip type checking by default, so many teams pair them with tsc --noEmit in continuous integration.
esbuild for ultrafast bundling and transforms
esbuild is designed for speed and can collapse an entire dependency graph into a single output. You can use it to build server code or to prepare a hybrid project that mixes client and server elements.
esbuild src/index.ts --platform=node --format=esm --outfile=dist/index.js
swc for a Rust powered pipeline
swc offers fast transforms and a flexible configuration file. It is a strong choice when you want speed with fine grained control over emitted JavaScript targets.
{
"jsc": {
"target": "es2022",
"parser": { "syntax": "typescript" }
}
}
tsc --noEmit to keep type checking clean. This gives you speed without sacrificing safety.
Source maps and production debugging
Source maps connect emitted JavaScript back to your TypeScript files. When configured correctly, error stacks point to the original source, which saves time during debugging. You can use inline maps during development and external maps for production deployments.
Compiler options for clean debugging
Enable sourceMap and inlineSources so your editor and Node’s inspector can locate original lines. External maps are often better in production because they reduce payload size while still giving traceability when you capture logs.
{
"compilerOptions": {
"sourceMap": true,
"inlineSources": true
}
}
Runtime support in Node
Node reads source maps automatically when the loader provides them. For modern setups, no extra flags are needed. If you use older runtime tools or process managers, confirm that source maps remain available in the deployed environment.