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:
mkdir my-node-project && cd my-node-projectnpm init -yInstall TypeScript and the essential type definitions:
npm install -D typescript @types/nodeCreate the TypeScript configuration:
{ "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:
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:
npm install -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-nCreate your ESLint configuration:
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:
{ "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):
npm install -D tsxNow you can run:
npm run lintnpm run buildnpm run devBest 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:
npm install expressnpm install -D @types/expressRun 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