TypeScript on Node.js
Run TypeScript on the server with confidence. You'll set up a Node-friendly tsconfig.json , add @types/node , understand ESM vs CommonJS , use tsx / ts-node in development, compile with tsc for production, and work with typed process and fs .
Learn TypeScript on Node.js in our free TypeScript course — an interactive lesson with runnable examples, a practice exercise and a quick reference.
Part of the free TypeScript course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn
💡 Real-World Analogy
TypeScript on Node is like writing in a language Node doesn't speak and using a translator . tsc is the careful translator that produces a polished JavaScript document ahead of time; tsx is the live interpreter that translates as you go. Either way, Node only ever hears JavaScript — the TypeScript is for you and the compiler.
1. A Node-Ready tsconfig.json
The config tells tsc what to emit and how to resolve imports. For modern Node, set "module" and "moduleResolution" to "NodeNext" , choose an outDir , and turn on strict . Read the real file here:
2. The Build-and-Run Cycle
Node runs JavaScript , so your TypeScript has to become JS first. Two modes cover everything: compile with tsc then run the output (production), or run the .ts directly with tsx / ts-node (development). The box below prints both flows.
3. The Typed process Global
Once @types/node is installed, Node's globals are fully typed. process.argv is a string[] of command-line arguments, and process.env holds environment variables (always string | undefined ). The box simulates process so it runs here:
4. ESM vs CommonJS
CommonJS uses require() and module.exports ; ES modules use import and export , enabled by "type": "module" . A classic gotcha: __dirname exists in CommonJS but not in ESM. The read-only block above shows the real syntax; the box below models both systems:
Your turn. Fill in the two blanks marked ___ to read a --port argument, then run it.
Common Errors (and the fix)
- ❌ "Cannot find name 'process'" — Node's types are missing. ✅ Install @types/node as a dev dependency.
- ❌ __dirname is not defined in ESM — it's CommonJS-only. ✅ Rebuild it from import.meta.url with fileURLToPath .
- ❌ "Cannot use import statement outside a module" — Node treated the file as CommonJS. ✅ Add "type": "module" to package.json .
- ❌ Running the .ts file with plain node — Node can't parse TypeScript. ✅ Compile with tsc first, or run with tsx .
Pro Tips
- 💡 Match the tools — "type": "module" in package.json pairs with "module": "NodeNext" in tsconfig.
- 💡 tsx for dev, tsc for ship — fast iteration locally, a real build for production.
- 💡 Import built-ins with the node: prefix — import fs from "node:fs" is explicit and future-proof.
- 💡 Coerce env vars — they're always strings; wrap process.env.PORT in Number(...) with a fallback.
Frequently Asked Questions
Mini-Challenge: A Config Loader
No blanks this time — build loadConfig() yourself (env, coerced port, boolean debug), run it, and match your output to the example.
🎉 Lesson Complete
- ✅ A Node tsconfig.json sets module / moduleResolution to NodeNext
- ✅ @types/node types process , fs , path , and the other built-ins
- ✅ tsx / ts-node run TypeScript in dev; tsc + node ship to prod
- ✅ ESM ( import ) vs CommonJS ( require ) is chosen with "type": "module"
- ✅ __dirname is rebuilt from import.meta.url in ES modules
- ✅ Next lesson: Building APIs with Express and TypeScript
Practice quiz
Why install @types/node in a Node TypeScript project?
- It provides type definitions for Node's built-in modules and globals
- It compiles your code
- It is the Node runtime
- It speeds up Node
Answer: It provides type definitions for Node's built-in modules and globals. @types/node ships the type declarations for process, fs, path, Buffer, and other Node built-ins so the compiler knows them.
What does the tsc command do?
- Installs Node types
- Starts a dev server
- Compiles TypeScript to JavaScript that Node can run
- Runs the TypeScript file directly
Answer: Compiles TypeScript to JavaScript that Node can run. tsc (the TypeScript compiler) emits plain JavaScript; Node then runs that compiled .js output.
Which tool lets you run a .ts file directly during development without a separate build step?
- npm
- tsx (or ts-node)
- eslint
- prettier
Answer: tsx (or ts-node). tsx and ts-node transpile and execute TypeScript on the fly, which is convenient for development.
In tsconfig.json, what does the "module" option control?
- The lint rules
- The output folder
- The Node version
- The module system of the emitted JavaScript (e.g. CommonJS or ESM)
Answer: The module system of the emitted JavaScript (e.g. CommonJS or ESM). "module" sets the module format tsc emits, such as "CommonJS" or "NodeNext"/"ESNext" for ES modules.
How does Node decide a project uses ES modules rather than CommonJS?
- "type": "module" in package.json (or a .mjs extension)
- It always uses ESM
- The presence of @types/node
- The file is large
Answer: "type": "module" in package.json (or a .mjs extension). Setting "type": "module" in package.json (or using .mjs) tells Node to treat .js files as ES modules; otherwise they are CommonJS.
Which syntax loads a module in CommonJS?
- include "x"
- require("x")
- import x from "x"
- load("x")
Answer: require("x"). CommonJS uses require() and module.exports; ES modules use import/export.
What is a clean way to get the current directory in an ES module, where __dirname is not defined?
- It is impossible in ESM
- Just use __dirname, it always works
- Use process.argv
- Derive it from import.meta.url with fileURLToPath
Answer: Derive it from import.meta.url with fileURLToPath. In ESM, __dirname and __filename are not defined; you reconstruct them from import.meta.url using fileURLToPath and path.dirname.
For a typical Node project, what moduleResolution setting matches Node's behaviour with ESM?
- "none"
- "classic"
- "NodeNext" (or "Node16")
- "browser"
Answer: "NodeNext" (or "Node16"). "NodeNext"/"Node16" tells tsc to resolve modules the way modern Node does, including ESM rules and file extensions.
After running tsc, what do you actually execute with Node?
- The node_modules folder
- The compiled .js output
- The tsconfig.json
- The .ts source files
Answer: The compiled .js output. tsc emits JavaScript (often into a dist/ folder); you then run that compiled .js, for example node dist/index.js.
Where does Node read command-line arguments and environment variables from?
- The process global (process.argv and process.env)
- The window object
- The fs module only
- import.meta
Answer: The process global (process.argv and process.env). Node's process global exposes process.argv for arguments and process.env for environment variables; @types/node types them.
Continue this course
- Previous: Testing TypeScript
- Next: Building APIs with Express and TypeScript