TypeScript tsconfig and Setup: Configure a Project Correctly
TypeScript projects start with a configuration file named tsconfig.json. This file tells the TypeScript compiler how to find your source files, where to place compiled JavaScript, and which type-checking rules to apply.
Quick answer: tsconfig.json is the main configuration file for a TypeScript project. It controls compiler settings such as strict mode, input and output folders, and which files TypeScript should compile.
Difficulty: Beginner
You'll understand this better if you know: basic JavaScript files, how folders and file paths work, and the difference between source code and generated output.
1. What Is tsconfig.json?
tsconfig.json is a JSON file that defines a TypeScript project. When you run the TypeScript compiler in a folder containing this file, the compiler reads the settings and uses them for the whole project.
- It marks a directory as a TypeScript project.
- It controls how the compiler reads your files.
- It defines output behavior such as build folders and source maps.
- It turns TypeScript from a single-file tool into a project-wide setup.
Without tsconfig.json, TypeScript still works for quick checks, but you lose most of the project structure and configuration that real applications need.
2. Why tsconfig Matters
A good TypeScript setup prevents confusion later in development. It helps you keep source files, generated files, and type-checking rules organized in one place.
TypeScript projects often grow quickly. A clear configuration makes it easier to:
- compile the right files and ignore build artifacts,
- catch type mistakes early with stricter checking,
- output JavaScript to a separate directory, and
- share the same rules with your team and your CI environment.
In practice, tsconfig.json is the difference between a working local experiment and a maintainable project setup.
3. Basic Syntax or Core Idea
A minimal TypeScript configuration usually starts with tsc --init. That command creates a starter tsconfig.json file.
Creating the config file
tsc --initThis command creates a default configuration in the current directory. After that, TypeScript uses the file when you run tsc without extra file arguments.
A minimal project configuration
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"strict": true,
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}Here, compilerOptions controls the compiler, include tells TypeScript which files belong to the project, and src is the folder containing your source code.
4. Step-by-Step Examples
Example 1: Set up a simple project structure
Start with a clean folder layout. Keep TypeScript source files in src and compiled files in dist.
project/
src/
index.ts
tsconfig.jsonThen add a simple source file.
const message: string = "Hello, TypeScript!";
console.log(message);When you run the compiler, TypeScript reads the config and generates JavaScript in the output directory.
Example 2: Compile into a separate output folder
This setup keeps generated JavaScript out of your source folder, which makes the project easier to manage.
{
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src/**/*.ts"]
}This configuration says: take TypeScript files from src and place compiled output into dist.
Example 3: Enable strict type checking
Strict mode catches more mistakes before your code runs.
{
"compilerOptions": {
"strict": true
}
}With strict mode on, TypeScript enforces safer checks such as possibly undefined values and implicit any usage.
Example 4: Add source files and keep build artifacts out
Use include and exclude together to control what the compiler sees.
{
"compilerOptions": {
"outDir": "dist"
},
"include": ["src/**/*"],
"exclude": ["dist", "node_modules"]
}This prevents TypeScript from trying to compile generated files or installed packages.
5. Practical Use Cases
- Building a Node.js application in TypeScript with output in dist.
- Creating a front-end TypeScript project that bundles source files from src.
- Maintaining a monorepo with multiple TypeScript packages, each with its own config.
- Sharing the same compiler rules across a team so everyone gets the same errors locally and in CI.
- Turning on strict type checking in an existing JavaScript-to-TypeScript migration.
6. Common Mistakes
Mistake 1: Compiling the output folder again
One common setup problem is letting TypeScript read files from the build output directory. That can cause repeated compilation, confusing file lists, or stale artifacts.
Problem: If dist is included in the project, TypeScript may try to compile generated files as if they were source files.
{
"compilerOptions": {
"outDir": "dist"
},
"include": ["**/*"]
}Fix: Limit input files to your source folder and exclude the build output directory.
{
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src/**/*"],
"exclude": ["dist"]
}This works because TypeScript only sees the real source files.
Mistake 2: Expecting TypeScript to run without a config
Beginners sometimes run tsc in a folder that does not contain tsconfig.json and expect project behavior.
Problem: Without a project file, TypeScript uses default behavior and may report tsconfig.json-related workflow confusion such as “Cannot find a tsconfig.json file at the specified directory.”
tscFix: Create a config file first, then run the compiler from the project root.
tsc --init
tscThe corrected workflow works because the compiler now has project settings to read.
Mistake 3: Putting source and output in the same folder
When compiled JavaScript lands beside your TypeScript source, it becomes harder to tell which files you should edit.
Problem: If the same directory contains both .ts and generated .js files, it is easy to edit the wrong file or commit generated output by accident.
{
"compilerOptions": {
"outDir": "src"
}
}Fix: Use a separate output folder such as dist.
{
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
}
}A separate output folder keeps source and build files clearly separated.
7. Best Practices
Practice 1: Turn on strict mode early
Strict mode helps TypeScript catch problems before they become runtime bugs. It is usually easier to enable it at the start than to retrofit it later.
{
"compilerOptions": {
"strict": true
}
}With stricter checks, you get clearer feedback while the codebase is still small.
Practice 2: Separate source and build output
Keeping src and dist separate reduces accidental edits and makes version control cleaner.
{
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"
}
}This layout also makes it easier to delete and rebuild output without touching your source code.
Practice 3: Keep the config small at first
New projects do not need every option turned on immediately. Start with the settings you actually need, then add more when a real requirement appears.
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"strict": true
},
"include": ["src"]
}A smaller config is easier to understand and less likely to contain conflicting options.
8. Limitations and Edge Cases
- tsconfig.json applies to a project root, but nested configs can override or extend it in larger codebases.
- include and exclude control which files are part of the project, but imported files can still be pulled in transitively.
- TypeScript configuration affects type checking and output generation, but it does not bundle files into a single browser-ready script.
- Different module targets such as CommonJS and ES2020 change the shape of emitted JavaScript.
- Some editor features use the nearest tsconfig.json, so a misplaced file can cause IntelliSense to behave unexpectedly.
- Setting noEmit to true is useful for type checking only, but it means no JavaScript files will be produced.
9. Practical Mini Project
Here is a small but complete TypeScript setup for a simple command-line script. It includes a project structure, configuration, and source file that compiles cleanly.
Project layout:
project/
src/
index.ts
tsconfig.jsontsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"strict": true,
"rootDir": "src",
"outDir": "dist",
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["dist"]
}src/index.ts:
function greet(name: string): string {
return `Hello, ${name}!`;
}
const output = greet("TypeScript");
console.log(output);Run the compiler from the project root. TypeScript reads the config, checks the code, and writes JavaScript to dist.
10. Key Points
- tsconfig.json defines how a TypeScript project is compiled and checked.
- tsc --init is the quickest way to create a starter config.
- strict, rootDir, and outDir are among the most important options.
- include and exclude help TypeScript find the right files.
- Separating source and output folders makes the project easier to maintain.
11. Practice Exercise
- Create a new folder with a src directory and an index.ts file.
- Generate a tsconfig.json file with tsc --init.
- Configure the project so compiled files go to dist.
- Turn on strict mode and make sure only files inside src are compiled.
Expected output: a working project where tsc produces JavaScript in dist without compiling build artifacts.
Hint: Use rootDir, outDir, include, and exclude together.
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"strict": true,
"rootDir": "src",
"outDir": "dist"
},
"include": ["src/**/*"],
"exclude": ["dist"]
}12. Final Summary
tsconfig.json is the foundation of a TypeScript project. It tells the compiler what to check, what to compile, and where to put the output. Once you understand the core options, you can keep your project consistent and easier to maintain.
The most important habits are simple: create a config with tsc --init, keep source files in src, send output to dist, and enable strict mode when possible. Those choices cover most everyday TypeScript setups.
From there, you can refine the config as your project grows by adding module settings, source maps, path aliases, or other options your build system needs. A clean setup today makes every later TypeScript change easier.