Short answer: To set up a TypeScript project from scratch, install Node.js, create a project folder, run npm init, install TypeScript as a dev dependency, create a tsconfig.json file, write your first .ts file, and compile it using npx tsc. For Node.js projects, also install @types/node.
Key takeaways
- Install TypeScript via npm as a dev dependency
- Configure tsconfig.json for strict mode
- Use separate source and dist directories
- For Node.js, install @types/node
- Set up a build script in package.json
- Enable source maps for easier debugging
What you will find here
- Why Set Up TypeScript from Scratch?
- Prerequisites
- Step-by-Step: Initialize the Project
- Configuring tsconfig.json for a Real Project
- Integrating with Node.js
- Adding a Build Script and Watch Mode
- Common Pitfalls and Best Practices
- Comparison: Default vs. Production-Ready Setup
- Managing Multiple Configuration Files
- Next Steps: Linting and Formatting
You want to add static typing to your JavaScript project. TypeScript gives you that safety net without sacrificing the flexibility of JS. Setting up a TypeScript project from scratch is straightforward once you understand the moving parts. This guide takes you through a minimal yet production-ready setup using Node.js and npm.

Why Set Up TypeScript from Scratch?
Using a starter template or a framework like Next.js with built-in TypeScript support is convenient, but it hides the configuration details. When you set up TypeScript from scratch, you control every option. You understand the compiler, the module system, and how types integrate with your runtime. This knowledge helps you debug configuration issues later and tailor TypeScript to your exact needs.
Starting from scratch also teaches you the minimal requirements. You can then scale up when your project demands stricter checks or more complex builds.
Prerequisites
You need Node.js installed on your machine. TypeScript runs on Node, and you’ll use npm to install it. If you haven’t already, download the latest LTS version from the official Node.js website. Verify your installation by running node --version and npm --version in your terminal.
You should also be comfortable with basic terminal commands and have a code editor ready. VS Code is a popular choice because of its first-class TypeScript support.
Step-by-Step: Initialize the Project
Follow these steps to create a new TypeScript project from an empty folder.
- Create a project folder:
mkdir my-typescript-projectandcd my-typescript-project. - Initialize npm: Run
npm init -yto create apackage.jsonfile with default values. You can edit the fields later. - Install TypeScript:
npm install --save-dev typescript. Installing it as a dev dependency keeps it out of production builds. - Create tsconfig.json: Run
npx tsc --initto generate a boilerplate configuration file. - Create your first TypeScript file: Make a
srcdirectory and addindex.tsinside it with a simple function. - Compile: Run
npx tscto compile the TypeScript files. By default, output goes to the same directory. We’ll change that soon.
That’s the basic setup. But a real project needs a better structure. Let’s refine it.

Configuring tsconfig.json for a Real Project
The tsconfig.json file is the heart of your TypeScript configuration. Here are the key options you’ll want to set up for a typical Node.js project.
Strict Mode
Enable strict: true to catch more errors at compile time. This turns on all strict type-checking options, including noImplicitAny and strictNullChecks. The earlier you catch type issues, the fewer runtime surprises you’ll have.
Output Directory
Set outDir to "./dist" to keep compiled JavaScript files separate from your source. Set rootDir to "./src" so TypeScript only compiles files from your source folder. This keeps your project clean.
Module System
For Node.js, set module to "commonjs" and target to "ES2020" or higher. This ensures your compiled code uses Node’s native module resolution.
Source Maps
Enable sourceMap: true to generate .map files. Source maps let you debug the original TypeScript code directly in your browser or Node debugger, rather than the compiled JavaScript.
Sample tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"outDir": "./dist",
"rootDir": "./src",
"sourceMap": true
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
Integrating with Node.js
If you’re building a Node.js application, you need type definitions for Node’s built-in modules like fs and path. Install them with npm install --save-dev @types/node. Without these, TypeScript will complain about missing types when you use require('fs') or import * as fs from 'fs'.
Now you can write TypeScript files that use Node APIs. For example, a simple HTTP server:
import * as http from 'http';
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello TypeScript!');
});
server.listen(3000, () => {
console.log('Server running on port 3000');
});
To run this, compile first (npx tsc) and then run the output: node dist/index.js. Or you can use ts-node to run TypeScript directly in development: npm install --save-dev ts-node and then npx ts-node src/index.ts.
Adding a Build Script and Watch Mode
Your package.json should include a build script so you don’t type npx tsc every time. Add these scripts:
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "ts-node src/index.ts"
}
For a better development experience, use TypeScript’s watch mode. Run npx tsc --watch to automatically recompile whenever you save a file. You can also add a script: "watch": "tsc --watch". This pairs well with nodemon for Node projects — nodemon restarts your server when compiled files change.
Common Pitfalls and Best Practices
Watch out for these common mistakes when setting up TypeScript from scratch:
- Missing @types/node: You’ll get errors like “Cannot find name ‘require’” or “Cannot find module ‘fs’”. Install the types and set
types: ["node"]in tsconfig if you want explicit control. - Not excluding dist from compilation: If you do not exclude the
distfolder, TypeScript may compile its own output again, causing infinite loops or duplicate declarations. Add"exclude": ["node_modules", "dist"]. - Ignoring strict mode: Skipping strict mode might let sloppy code through. It’s easier to start strict and loosen only where needed than to tighten later.
- Forgetting esModuleInterop: Without
esModuleInterop: true, importing CommonJS modules can be awkward. Enable it for a more natural import syntax. - Mismatched rootDir and outDir: Ensure your
rootDirincludes all source files. If you have files outsidesrc, they won’t be compiled unless you adjust the include patterns. - Using relative paths incorrectly: When you set
outDir, the folder structure insidedistmirrors the source. If your imports include deep relative paths, they still work because the structure is preserved.
Comparison: Default vs. Production-Ready Setup
The table below highlights the differences between a minimal TypeScript setup and one you’d use for a real project.
| Feature | Default npx tsc –init | Production-Ready Setup |
|---|---|---|
| Structural typing | strict: false | strict: true |
| Output folder | Same as source | ./dist |
| Source maps | false | true |
| Node type definitions | Not included | @types/node installed |
| Watch mode | Not configured | tsc –watch script |
Managing Multiple Configuration Files
As your project grows, you might need different TypeScript configurations for different environments. For example, you may want a stricter production build and a more lenient development build. You can create multiple tsconfig files and extend a base config. Create a tsconfig.base.json with shared options, then tsconfig.json for development and tsconfig.prod.json for production. Use the extends field:
// tsconfig.prod.json
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"sourceMap": false
},
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}
Then run npx tsc -p tsconfig.prod.json to build with the production config. This pattern keeps your configurations DRY and maintainable.
Next Steps: Linting and Formatting
Once your TypeScript project compiles cleanly, consider adding ESLint and Prettier. ESLint with the @typescript-eslint plugin catches code-quality issues, while Prettier enforces consistent formatting. Install them as dev dependencies and create configuration files for each. Many teams also integrate Husky to run linting before commits.
Your setup is now ready for development. Start writing code with confidence, knowing TypeScript has your back.
Frequently asked questions
What is the easiest way to set up TypeScript from scratch?
The easiest way is to install TypeScript via npm, run npx tsc –init to create a tsconfig.json, then write a .ts file and compile it. For a Node.js project, also install @types/node. Use scripts in package.json to automate builds.
Do I need to install TypeScript globally?
It is recommended to install TypeScript as a dev dependency per project (npm install –save-dev typescript) rather than globally. This ensures consistent versions across your team and avoids version conflicts.
How do I configure TypeScript for Node.js?
Set module to commonjs, target to ES2020, enable esModuleInterop, and install @types/node. Also set strict to true, outDir to ./dist, and rootDir to ./src for a clean build output.
What is the difference between tsc and ts-node?
tsc compiles TypeScript to JavaScript, which you then run with Node. ts-node runs TypeScript directly without a separate compile step, making it convenient for development. Use tsc for production builds and ts-node for rapid iteration.
How do I debug TypeScript code?
Enable source maps in tsconfig (sourceMap: true). Then you can debug the original TypeScript files using Node’s inspector (node –inspect dist/index.js) or your editor’s debugger. Tools like Visual Studio Code support breakpoints in .ts files when source maps are present.
