Skip to main content
  1. Posts/

Using `tsc` and `ts-node` for production builds

·383 words·2 mins
Table of Contents
A short TID about choosing how to run a TypeScript server in production. 📝

What I was comparing #

When a Node.js server is written in TypeScript, there are two common ways to run it.

  • Compile the TypeScript with tsc, then run the generated JavaScript with Node.js.
  • Use ts-node to transform and execute TypeScript during startup.

The difference is not only a command. It changes when TypeScript is transformed and what the production process has to carry.

Using tsc #

tsc compiles the project according to tsconfig.json.

tsc -p ./
node dist/server.js

The build step creates JavaScript before the server starts. A production image or deployment can then contain the compiled output and the runtime dependencies needed to execute it.

This also gives the build pipeline a clear failure point. If the TypeScript does not compile, the deployment can stop before starting the server.

Using ts-node #

ts-node hooks into Node.js module loading and transforms TypeScript when a file is loaded.

ts-node --transpile-only src/server.ts

This is convenient during development because the source files can be executed without a separate compile command. The process also needs the TypeScript execution tool and the source configuration at runtime.

The --transpile-only option skips type checking. That can shorten the startup path, but type checking still needs to happen in a separate build or CI step.

The production decision #

For production, I prefer compiling with tsc and running the generated JavaScript.

{
  "scripts": {
    "build": "tsc -p ./",
    "start": "node dist/server.js",
    "dev": "ts-node src/server.ts"
  }
}

This separates development convenience from the production runtime. It also makes the artifact that will be deployed explicit.

That does not make ts-node unusable in production. It can be a reasonable choice when the deployment already supports runtime TypeScript execution and the build and type-check steps are enforced elsewhere. The important part is knowing whether the server is failing during compilation, startup transformation, or application startup.

Conclusion #

tsc and ts-node solve related but different problems. tsc prepares JavaScript before the process starts, while ts-node transforms TypeScript as Node.js loads it.

For the production build flow I was considering, the precompiled output from tsc made the deployment boundary easier to understand. I would still use ts-node when the shorter development loop matters more than producing a separate artifact.

References #