TypeScript in a Node.js Project

 by Robin Wieruch
 - Edit this Post

Setting up a TypeScript project with Node.js may seem like a hassle at first, but with the right steps, you'll have everything running smoothly in no time. Whether you're building a small script or a full-fledged application, this guide will walk you through the entire process.

We'll start from scratch, configure TypeScript, and set up a simple development environment with best practices. Let's dive in!

Setup Node.js Project

First, you need a dedicated folder for your project. Open your terminal and run the following commands:

// Command Line
mkdir my-project
cd my-project
npm init -y

Let's break down what each command does:

  • mkdir my-project: Creates a new project directory.
  • cd my-project: Moves into the new directory.
  • npm init -y: Initializes a new package.json file with default values.

This package.json file is essential for a Node.js project as it manages dependencies and scripts for your project.

TypeScript in Node.js

Now, let's install TypeScript as a development dependency and create a configuration file:

// Command Line
npm install --save-dev typescript
touch tsconfig.json

Let's break down what each command does:

  • npm install --save-dev typescript: Installs TS locally for your project.
  • touch tsconfig.json: Creates a TypeScript configuration file.

Next, add the following configuration to your tsconfig.json file:

// tsconfig.json
{
"compilerOptions": {
/* Modern JavaScript & Browser Compatibility: */
"target": "ESNext", // Uses the latest ECMAScript features for modern JavaScript support
/* Module System Settings: */
"module": "NodeNext", // Configures Node.js to use ESM module system
"rootDir": "src", // Specifies the source directory for your code
"outDir": "dist", // Specifies the output directory for compiled files
"sourceMap": true, // Enables source maps for easier debugging
/* Module Resolution Strategy: */
"moduleResolution": "NodeNext", // Resolves modules using Node’s ESM strategy
"moduleDetection": "force", // Forces TypeScript to treat files as modules
/* Interoperability and File Consistency: */
"esModuleInterop": true, // Ensures compatibility between CommonJS and ESM modules
"forceConsistentCasingInFileNames": true, // Prevents case-sensitivity issues across platforms
/* Strict Type-Checking: */
"strict": true, // Enables strict type-checking for fewer runtime errors
"noUncheckedIndexedAccess": true, // Enforces type safety for array/object accesses
"noImplicitOverride": true, // Enforces explicit use of `override` for methods overriding base class methods
"noImplicitAny": true, // Prevents the use of `any` type unless explicitly defined
"skipLibCheck": true, // Skips type-checking of declaration files for faster compilation
"resolveJsonModule": true, // Allows importing JSON files as modules
"declaration": true, // Generates `.d.ts` files for type definitions
"allowSyntheticDefaultImports": true, // Allows default imports for CommonJS modules
"allowImportingTsExtensions": true, // Allows importing `.ts` files with their extensions
"verbatimModuleSyntax": true, // Keeps the `import`/`export` syntax as-is without transformation
// Include modern ECMAScript (ES2022) and DOM APIs for frontend
"lib": ["ES2022", "DOM"] // Include ES2022 features and DOM APIs for frontend development
// Uncomment this for backend code without DOM APIs
/* "lib": ["ES2022"] */
},
"include": ["src"], // Includes the `src` directory in the project
"exclude": ["node_modules", "dist"] // Excludes `node_modules` and `dist` directories from the project
}

Optionally add the following lines for JavaScript support in a TypeScript project:

// tsconfig.json
{
"compilerOptions": {
...
"allowJs": true,
"checkJs": true
}
}

If we are fully committing to ESM, add this to the package.json:

{
"type": "module"
}

Source Folder and Entry File

Create a src folder and an index.ts file inside it:

// Command Line
mkdir src
touch src/index.ts

Now, add a simple TypeScript script in src/index.ts:

// src/index.ts
console.log("Hello world!");

This will serve as our starting point to ensure everything is working correctly.

Run & Compile TypeScript Files in Node.js

To run TypeScript files directly without compiling them first, install tsx which is a popular TypeScript runner. An alternative would be to use ts-node:

// Command Line
npm install tsx --save-dev

You can also use type stripping natively in Node.js, but tsx fully supports TypeScript features. Now, update your package.json scripts to use tsx:

// package.json
"scripts": {
"dev": "tsx src/index.ts",
"build": "tsc",
"start": "node dist/index.js"
}

Let's break down what each script does:

  • "dev": "tsx src/index.ts":
    • Runs the project in development mode using tsx. This script is used during development.
  • "build": "tsc":
    • Compiles TypeScript files into JavaScript with TypeScript compiler (tsc). The compiled files are stored in the dist folder.
  • "start": "node dist/index.js":
    • Runs the compiled JavaScript files. This script is used in production.

For automatic reloading, update the dev script:

// package.json
"scripts": {
"dev": "tsx --watch src/index.ts",
"build": "tsc",
"start": "node dist/index.js"
}

The --watch flag makes tsx automatically recompile and reload files when changes are made.

Environment Variables in Node.js

Many applications require sensitive API keys and environment variables. The best practice is to store them in a .env file instead of hardcoding them. Create a .env file in your project directory with the following content:

# .env
OPENAI_API_KEY="sk-proj-123abc"

Then, modify src/index.ts to read the environment variable:

// src/index.ts
console.log(process.env.OPENAI_API_KEY);

To ensure environment variables are recognized by TypeScript, install Node.js type definitions:

// Command Line
npm install @types/node --save-dev

If you're using Node.js 20.6.0 or newer, you can load environment variables directly using the --env-file flag:

// package.json
"scripts": {
"dev": "tsx --watch --env-file=.env src/index.ts",
"build": "tsc",
"start": "node --env-file=.env dist/index.js"
}

For a more sophisticated approach, consider using the dotenv package:

// Command Line
npm install dotenv

Modify src/index.ts to load the .env file using dotenv:

// src/index.ts
import "dotenv/config";
console.log(process.env.OPENAI_API_KEY);

Update the package.json scripts accordingly:

// package.json
"scripts": {
"dev": "tsx --watch src/index.ts",
"build": "tsc",
"start": "node dist/index.js"
}

Now, your project can securely read environment variables.


That's it! You've successfully set up a TypeScript project with Node.js. Here's a quick recap of what we did:

  • Created a new Node.js project with npm init
  • Installed and configured TypeScript
  • Set up a source directory with a TypeScript entry file
  • Installed tsx for running TypeScript files efficiently
  • Configured environment variables using .env
  • Used dotenv for better environment variable management

Now you're ready to start building your TypeScript-powered Node.js application!

Keep reading about 

Deno is a new runtime for JavaScript and TypeScript. If this doesn't tell you much and you don't know what to expect, then take this statement as secondary introduction: Ryan Dahl, inventor of Node.js…

TypeScript is getting more popular these days for frontend and backend applications. Here you will learn how to set up TypeScript in Node.js for a backend project. The previous tutorial already…

The Road to React

Learn React by building real world applications. No setup configuration. No tooling. Plain React in 200+ pages of learning material. Learn React like 50.000+ readers.

Get it on Amazon.