Linting Basics
8 examples to get you started with Linting & Formatting - 6 basic and 2 intermediate.
Prerequisites
- Node.js 24.18.0 project with TypeScript 5.6+.
- Install ESLint 9 flat config stack:
npm install -D eslint@9 typescript-eslint @eslint/jsBasic Examples
1. Minimal ESLint Flat Config
ESLint 9 uses eslint.config.js (or .mjs) instead of legacy .eslintrc.
// eslint.config.js
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
{
ignores: ["dist/**", "node_modules/**"],
}
);- Flat config is an array of config objects merged in order.
ignoresreplaces.eslintignore.typescript-eslintbundles parser and plugin for TS.
2. Add Lint Script
Wire lint into daily workflow and CI.
{
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix"
}
}- Run
npm run lintbefore push; fail CI on errors. --fixhandles import order and simple style rules automatically.
Related: Linting Best Practices - zero-warning policy
3. Type-Aware Rules
Enable type-checked linting for stricter correctness.
export default tseslint.config(
...tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
}
);projectService(TS 5.6+) simplifiesparserOptions.projectsetup.- Type-aware rules catch floating promises and unsafe
anyusage. - Slightly slower; scope to
src/**if needed.
4. Node Globals and ESM
Tell ESLint you run on Node with ES modules.
{
files: ["**/*.ts"],
languageOptions: {
ecmaVersion: 2022,
sourceType: "module",
globals: {
...globals.node,
},
},
}npm install -D globalssourceType: "module"matches"type": "module"inpackage.json.- Prevents false
no-undefonprocessandBuffer.
5. Ban console.log in Production Code
Keep logs structured via your logger, not raw console in src/.
{
files: ["src/**/*.ts"],
rules: {
"no-console": ["error", { allow: ["warn", "error"] }],
},
}- Tests and scripts can use a separate config block with
no-console: off. - Pair with Pino or org logger in application code.
Related: Prettier Integration - formatting separate from lint
6. Lint Test Files Separately
Relax rules where mocks and any are common.
{
files: ["test/**/*.ts", "**/*.test.ts"],
rules: {
"@typescript-eslint/no-explicit-any": "off",
"no-console": "off",
},
}- Tests benefit from pragmatism; production
src/stays strict. - Still ban unused vars in tests to catch dead setup code.
Intermediate Examples
7. Monorepo Root Config
Share one ESLint config across workspaces.
// eslint.config.js (root)
import base from "./packages/eslint-config/index.js";
export default [
...base,
{
files: ["apps/api/**/*.ts"],
rules: { "no-console": "error" },
},
];- Extract shared config to
packages/eslint-configfor reuse. - Apps extend with service-specific overrides only.
Related: Import Boundaries - architectural rules
8. CI Lint Gate
Fail PRs on lint errors and warnings if you adopt zero-warning policy.
- run: npm ci
- run: npm run lint -- --max-warnings 0--max-warnings 0turns warnings into failures.- Run lint after install, parallel to typecheck for speed.
Related: Typecheck in CI - complementary gate
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.