Yevhen Klymentiev
dark
light
console
darkness
y.klymentiev@gmail.com
Reusable SnippetsPractical utility code for everyday use — custom-built and ready to share

BE Node.js (TS)

Step-by-step setup for a Node.js backend (TypeScript) with ESLint v9 flat config, typescript-eslint v8, Prettier, Jest + ts-jest, Husky v9, and Semantic Release.

1. Install dev dependencies

File
Copied!
1npm install -D \
2  typescript ts-node @types/node \
3  eslint @eslint/js globals typescript-eslint \
4  eslint-config-prettier eslint-plugin-prettier \
5  prettier \
6  jest ts-jest @types/jest supertest @types/supertest \
7  husky lint-staged \
8  @commitlint/config-conventional @commitlint/cli \
9  semantic-release @semantic-release/changelog @semantic-release/git \
10  @semantic-release/github @semantic-release/commit-analyzer \
11  @semantic-release/release-notes-generator

Note: typescript-eslint v8 is a unified package that replaces the separate @typescript-eslint/parser and @typescript-eslint/eslint-plugin.

2. Initialize TypeScript

File
Copied!
npx tsc --init

Recommended settings in tsconfig.json:

JSON
Copied!
1{
2  "compilerOptions": {
3    "target": "ES2021",
4    "module": "CommonJS",
5    "moduleResolution": "node",
6    "outDir": "dist",
7    "rootDir": "src",
8    "esModuleInterop": true,
9    "skipLibCheck": true,
10    "strict": true
11  }
12}

3. Create eslint.config.mjs

JavaScript
Copied!
1import js from '@eslint/js';
2import globals from 'globals';
3import tseslint from 'typescript-eslint';
4import prettierConfig from 'eslint-config-prettier';
5import prettier from 'eslint-plugin-prettier';
6
7export default tseslint.config(
8  { ignores: ['dist'] },
9  {
10    extends: [js.configs.recommended, ...tseslint.configs.recommended],
11    files: ['**/*.ts'],
12    languageOptions: {
13      ecmaVersion: 'latest',
14      globals: { ...globals.node },
15    },
16    plugins: { prettier },
17    rules: {
18      '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
19      'prettier/prettier': 'error',
20    },
21  },
22  prettierConfig,
23);

Note: Use .mjs extension to force ESM syntax for the config regardless of the project's "type" field.

4. Create .prettierrc

JSON
Copied!
1{
2  "singleQuote": true,
3  "trailingComma": "all",
4  "printWidth": 100,
5  "tabWidth": 2,
6  "semi": true
7}

5. Configure Husky and lint-staged

Add to package.json:

JSON
Copied!
1{
2  "scripts": {
3    "prepare": "husky"
4  },
5  "lint-staged": {
6    "*.ts": ["eslint --fix", "prettier --write"],
7    "*.{json,md,yml}": ["prettier --write"]
8  }
9}

Initialize Husky and set up hooks:

File
Copied!
1npx husky init
2echo "npx lint-staged" > .husky/pre-commit
3echo "npx --no -- commitlint --edit \"$1\"" > .husky/commit-msg

Note: Husky v9 replaced husky install with husky init. The prepare script is now just "husky".

6. Create commitlint.config.js

JavaScript
Copied!
1module.exports = {
2  extends: ['@commitlint/config-conventional'],
3};

7. Create jest.config.js

JavaScript
Copied!
1/** @type {import('jest').Config} */
2module.exports = {
3  preset: 'ts-jest',
4  testEnvironment: 'node',
5  testMatch: ['**/tests/**/*.test.ts'],
6};

8. Create release.config.js

JavaScript
Copied!
1module.exports = {
2  branches: ['main'],
3  plugins: [
4    '@semantic-release/commit-analyzer',
5    '@semantic-release/release-notes-generator',
6    [
7      '@semantic-release/changelog',
8      {
9        changelogFile: 'CHANGELOG.md',
10        changelogTitle: '# Changelog',
11      },
12    ],
13    [
14      '@semantic-release/git',
15      {
16        assets: ['CHANGELOG.md', 'package.json'],
17        message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}',
18      },
19    ],
20    '@semantic-release/github',
21  ],
22};

In CI/CD, make sure GITHUB_TOKEN is available in the environment.

9. Add npm scripts to package.json

JSON
Copied!
1{
2  "scripts": {
3    "start": "node dist/index.js",
4    "build": "tsc",
5    "dev": "ts-node src/index.ts",
6    "lint": "eslint .",
7    "format": "prettier --write .",
8    "test": "jest",
9    "test:watch": "jest --watch",
10    "release": "semantic-release"
11  }
12}

10. Optional: VSCode settings

JSON
Copied!
1{
2  "editor.formatOnSave": true,
3  "editor.codeActionsOnSave": {
4    "source.fixAll.eslint": "explicit"
5  },
6  "eslint.validate": ["typescript"],
7  "prettier.enable": true
8}