Skip to content

How to Set Up a Modern Node.js Project with TypeScript and ESLint

Problem

I needed to set up a new Node.js project from scratch. Not just a barebones package.json, but something production-ready with TypeScript, linting, and proper tooling. Every time I start a new project, I have to remember which packages to install, which configs to create, and how to wire everything together.

So I wrote this guide for future-me. And now you can use it too.

Initialize the Project

Start with npm init:

terminal
mkdir my-node-project && cd my-node-project
npm init -y

Install TypeScript and the essential type definitions:

terminal
npm install -D typescript @types/node

Create the TypeScript configuration:

tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

This configuration sets you up with strict type checking, ES2022 features, and proper module resolution for modern Node.js development.

Create your source directory and a simple entry point:

src/index.ts
interface Config {
port: number;
env: string;
}
function bootstrap(config: Config): void {
console.log(`Starting server in ${config.env} mode on port ${config.port}`);
}
bootstrap({ port: 3000, env: "development" });

Set Up ESLint with TypeScript

Now the important part: ESLint with typescript-eslint. This is the standard for linting TypeScript projects in 2026.

Install the required packages:

terminal
npm install -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-n

Create your ESLint configuration:

eslint.config.js
const tseslint = require("typescript-eslint");
module.exports = tseslint.config(
{
files: ["**/*.ts"],
languageOptions: {
parser: require("@typescript-eslint/parser"),
parserOptions: {
ecmaVersion: 2022,
sourceType: "module",
},
},
plugins: {
"@typescript-eslint": require("@typescript-eslint/eslint-plugin"),
n: require("eslint-plugin-n"),
},
rules: {
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-explicit-any": "warn",
"n/no-missing-import": "off",
"n/no-unpublished-import": "error",
},
},
{
ignores: ["dist", "node_modules"],
}
);

Add lint and type-check scripts to your package.json:

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

You’ll need tsx for development (it provides hot reloading and TypeScript execution):

terminal
npm install -D tsx

Now you can run:

terminal
npm run lint
npm run build
npm run dev

Best Practices

A few things worth doing from day one:

Use strict mode. The strict: true flag in tsconfig.json enables all strict type-checking options. Don’t disable it. It catches real bugs.

Install type definitions for everything. When you add a new dependency, check if it has @types:

terminal
npm install express
npm install -D @types/express

Run lint before you commit. Make it a habit. It costs nothing and catches obvious mistakes.

Keep your TypeScript and ESLint configs in sync. If you change your target ECMAScript version in tsconfig.json, update the ecmaVersion in your ESLint config too.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments