A TypeScript file cannot run as it is, because browsers and JavaScript engines do not understand type annotations. Something has to remove the types first. That something is either the TypeScript compiler (tsc), which also checks the types, or a faster tool that only strips them. The quickest way to run the code on this page is the Run button:
Output:
[x] Install TypeScript
[ ] Run a .ts file
Every runnable block in these docs works the same way: the code is type-checked by TypeScript 7 with strict on, and it runs only if there are no type errors. For longer experiments, the TypeScript playground is the same editor on a page of its own. The rest of this page is about running .ts files on your own machine.
The Options at a Glance
| Command | Checks types | Needs a build step | Supports enum, namespace, parameter properties |
|---|---|---|---|
npx tsc then node dist/index.js | Yes | Yes | Yes |
node index.ts (Node.js 22.18+, 23.6+) | No | No | No |
npx tsx index.ts | No | No | Yes |
npx ts-node index.ts | Yes | No | Yes, but not with TypeScript 7 |
deno run index.ts | No (deno check does) | No | Yes |
bun index.ts | No | No | Yes |
The column that surprises people is the first one: most of the fast options run code that has type errors in it. A typical project runs code with one of them and runs tsc --noEmit separately, in the editor and in CI, to catch the errors.
Compile with tsc, Then Run with Node
This is the approach that works everywhere and checks everything. With TypeScript installed in the project and a tsconfig.json that sets "rootDir": "./src" and "outDir": "./dist":
npx tsc
node dist/index.js
tsc type-checks all files, then writes .js files to dist. For a single file without a project, pass the file name. It then uses the default options and writes index.js next to index.ts:
npx tsc index.ts
node index.js
(If the folder has a tsconfig.json, tsc refuses file names with error TS5112; run plain npx tsc, or add --ignoreConfig.)
By default tsc still writes the JavaScript when there are type errors, so node can run a program that failed the check. Add "noEmitOnError": true to the config to prevent that, or chain the commands in a script so the second step only runs if the first succeeds:
{
"scripts": {
"build": "tsc",
"start": "tsc && node dist/index.js"
}
}
For development, npx tsc --watch recompiles on every save.
Run TypeScript Directly with Node.js
Current Node.js runs .ts files itself:
node index.ts
Node strips the type annotations, replacing them with whitespace so line numbers in stack traces still match, and runs what is left. This is on by default since Node.js 23.6.0 and 22.18.0, prints no warning since 24.3.0 and 22.18.0, and was marked stable in Node.js 24.12.0 and 25.2.0. Earlier releases that have the feature (22.6 to 22.17, and 23.0 to 23.5) need the flag: node --experimental-strip-types index.ts.
Four rules come with it:
- No type checking. A file with
const age: number = "forty"runs and printsforty. - Erasable syntax only. Anything that has to become JavaScript code, rather than disappear, is rejected:
enum,namespaceblocks with runtime code, constructor parameter properties likeconstructor(private name: string), andimport x = require()aliases. Node stops withSyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only mode. tsconfig.jsonis ignored. Options such aspathsortargethave no effect.- Imports need real file names. Write
import { add } from "./math.ts", with the extension, and mark type-only imports withtype:import { add, type Pair } from "./math.ts". Withouttype, Node looks for a runtime export calledPairand fails withSyntaxError: The requested module './math.ts' does not provide an export named 'Pair'.
Two compiler options make tsc enforce the same rules, so the editor warns you before Node does: "erasableSyntaxOnly": true reports error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled. on an enum, and "verbatimModuleSyntax": true requires the type keyword on type-only imports. To keep writing .ts extensions in imports and still compile with tsc, add "rewriteRelativeImportExtensions": true, which turns ./math.ts into ./math.js in the output.
Node.js 24 also has --experimental-transform-types, which generates code for enums and parameter properties instead of rejecting them. It prints an ExperimentalWarning, and Node.js 26 removed the flag, so do not build on it.
This block uses two features that node index.ts rejects. It runs here because the editor compiles it with the TypeScript compiler, which generates JavaScript for both:
The erasable version of the same code uses a const object and an ordinary field, which Node can run as is:
tsx
tsx runs a TypeScript file in one step, with no configuration and no restrictions on syntax:
npm install --save-dev tsx
npx tsx index.ts
npx tsx watch index.ts # rerun on every change
It transforms the code with esbuild, so enums, namespaces and parameter properties work, and imports without extensions resolve the way they do in a bundler. Like Node's type stripping, it does not type-check. It is the common choice for scripts, dev servers and tests on Node.js versions that predate type stripping, or when the code uses syntax that Node rejects.
ts-node
ts-node was the standard way to run TypeScript on Node.js for years, and it is still what many tutorials and older projects use (npx ts-node index.ts, node -r ts-node/register). It type-checks by default, using the TypeScript compiler's JavaScript API.
That API is exactly what TypeScript 7 does not ship: its compiler is a native program, and the typescript 7 package exposes no compiler API to JavaScript. With TypeScript 7 installed, ts-node crashes before running anything:
TypeError: Cannot read properties of undefined (reading 'fileExists')
at readConfig (/project/node_modules/ts-node/dist/configuration.js:91:33)
ts-node's latest release, 10.9.2, dates from December 2023. For new code use tsx or node index.ts. An existing setup that depends on ts-node keeps working if the project stays on TypeScript 6 (npm install --save-dev typescript@6) and has a tsconfig.json, even an empty {}. Without one, ts-node falls back to built-in defaults that include the node10 module resolution TypeScript 6 deprecated, and npx ts-node index.ts exits without running the file or printing an error.
Deno and Bun
Both runtimes treat TypeScript as a first-class file type:
deno run index.ts # runs without checking
deno check index.ts # type-checks, reports errors, runs nothing
bun index.ts # runs without checking
Neither needs typescript installed or a tsconfig.json, and both support enum and the other non-erasable features. Deno ships its own copy of the TypeScript compiler for deno check. Bun only strips types, so in a Bun project you still install typescript and run tsc --noEmit to find type errors.
Type Errors Stop the Program Only with tsc
Only the paths that run tsc first refuse to run a program with type errors. The editor on this page is one of them, so this block stops at the compiler:
index.ts(6,21): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
Saved as a file and run with node index.ts, npx tsx index.ts or bun index.ts, the same code runs and prints 12, because 3 * "4" converts the string. That is the reason to keep tsc --noEmit in the loop even when a faster tool runs the code:
{
"scripts": {
"dev": "tsx watch src/index.ts",
"typecheck": "tsc --noEmit"
}
}
Which One Should You Use?
- Learning, or a quick test: the Run button on these pages, or the playground.
- A script or small tool on a current Node.js:
node index.ts, witherasableSyntaxOnlyin the config so the editor flags anything Node would reject. - Any Node.js project, any syntax:
tsxto run,tsc --noEmitto check. - A library or anything you publish:
tsc, because it also writes the.d.tsfiles your users need. - Front end code: your bundler or framework (Vite, Next.js, Angular CLI) runs the TypeScript for you; add
tsc --noEmitfor the check.
Frequently Asked Questions
How do I run a TypeScript file?
The classic way is two steps: npx tsc compiles .ts to .js, then node dist/index.js runs the output. On Node.js 22.18 or 23.6 and later you can also run node index.ts directly, as long as the file only uses type syntax that can be erased. npx tsx index.ts runs any TypeScript file in one step.
Can Node.js run TypeScript directly?
Yes. Since Node.js 23.6 and 22.18, node file.ts works without flags: Node removes the type annotations and runs the rest. It does not type-check, it ignores tsconfig.json, and it rejects syntax that needs code generation, such as enum, namespace with runtime code and constructor parameter properties.
Does ts-node work with TypeScript 7?
No. ts-node calls the compiler's JavaScript API, which the typescript 7 package does not provide, so it crashes at startup (Cannot read properties of undefined (reading 'fileExists')). Its last release is 10.9.2 from December 2023. Use tsx, Node's own type stripping, or keep ts-node with TypeScript 6.
What is the difference between tsx and ts-node?
tsx only removes types (with esbuild) and runs the result, so it starts fast and never reports type errors. ts-node type-checks by default using the TypeScript compiler, which makes it slower and ties it to the compiler's JavaScript API. Most projects now pair tsx or node file.ts for running with tsc --noEmit for checking.
Is there an online TypeScript sandbox?
Yes. The code blocks on these docs pages and the TypeScript playground on Coddy compile your code with TypeScript 7 and run it, showing compiler errors or the program's output. The official TypeScript Playground on typescriptlang.org shows the emitted JavaScript and the errors.