Skip to content

Template

TypeScript

bash
pnpm install -D typescript
pnpm install -D @types/node nodemon @typescript-eslint/eslint-plugin @typescript-eslint/parser npm-run-all eslint

Package.json

json
{
  "scripts": {
    "dev": "npm-run-all --parallel watch:typescript watch:server",
    "watch:typescript": "tsc --watch",
    "watch:server": "nodemon ./dist/index.js",
  },
}

Development without nodemon

base
pnpm install -D typescript @types/node @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint tsx globals @eslint/js typescript-eslint

Eslint

.eslintrc.json

json
{
  "env": {
    "browser": true,
    "es2021": true
  },
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended"
  ],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": "latest",
    "sourceType": "module"
  },
  "plugins": [
    "@typescript-eslint"
  ],
  "rules": {
    "indent": [
      "error",
      2,
      {
        "SwitchCase": 1
      }
    ],
    /* "linebreak-style": [
        "error",
        "windows"
    ], */
    "quotes": [
      "error",
      "single"
    ],
    "semi": [
      "error",
      "always"
    ],
    "space-before-blocks": [
      "error",
      "always"
    ],
    "space-before-function-paren": [
      "error",
      {
        "anonymous": "never",
        "named": "never",
        "asyncArrow": "always"
      }
    ],
    "space-infix-ops": [
      "error",
      {
        "int32Hint": false
      }
    ],
    "no-console": [
      "error",
      {
        "allow": [
          "warn",
          "error"
        ]
      }
    ],
    "no-multiple-empty-lines": [
      "error",
      {
        "max": 1,
        "maxBOF": 0,
        "maxEOF": 1
      }
    ],
    "no-duplicate-case": "error",
    "keyword-spacing": [
      "error",
      {
        "before": true,
        "after": true,
        "overrides": {
          "switch": {
            "after": false
          }
        }
      }
    ],
    "no-unused-vars": "off",
    "require-await": "warn",
    "no-return-await": "error",
    "@typescript-eslint/no-unused-vars": [
      "warn", // or "error"
      {
        "argsIgnorePattern": "^_",
        "ignoreRestSiblings": true
        /* "varsIgnorePattern": "^_",
        "caughtErrorsIgnorePattern": "^_" */
      }
    ]
  }
}

.eslintignore

dist
node_modules

Backend template

sh
pnpm install --save-dev @types/compression @types/cors @types/express @types/node @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint typescript nodemon npm-run-all

Backend template 2026-06 (Pure nodejs)

Script

sh
mkdir my-service
cd my-service

pnpm init

pnpm add -D \
  typescript \
  tsx \
  eslint \
  @eslint/js \
  typescript-eslint \
  @types/node \
  globals

npx tsc --init
mkdir src
touch src/index.ts

package.json

json
{
  "type": "module",
  "scripts": {
    "dev": "tsx watch src/index.ts",
    "start": "tsx src/index.ts",
    "build": "tsc",
    "lint": "eslint ."
  }
}

tsconfig.json

json
{
  "compilerOptions": {
    "target": "ES2023",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",

    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,

    "rootDir": "src",
    "outDir": "dist",

    "sourceMap": true,
    "declaration": true,

    "types": ["node"],

    "skipLibCheck": true,
    "isolatedModules": true
  },
  "include": ["src"]
}

eslint.config.js

ts
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";

export default tseslint.config(
  {
    ignores: ["dist"]
  },

  js.configs.recommended,

  ...tseslint.configs.recommended,

  {
    languageOptions: {
      globals: {
        ...globals.node
      }
    }
  }
);

Backend template 2026-06 (Express)

Install

sh
pnpm add express compression cors 

pnpm add -D \
  typescript \
  tsx \
  eslint \
  @eslint/js \
  typescript-eslint \
  @types/node \
  @types/express \
  @types/compression \
  @types/cors \
  globals

server.ts

ts
import compression, { type CompressionFilter } from "compression";
import cors from "cors";
import dotenv from "dotenv";
import express, { type Request, type Response } from "express";
import http from "node:http";

dotenv.config({
  path: process.env.NODE_ENV ? `.env.${process.env.NODE_ENV}` : ".env",
});

const port = Number(process.env.PORT ?? 8080);

const app = express();

const compressionFilter: CompressionFilter = (req, res) => {
  if (req.headers["x-no-compression"]) {
    return false;
  }

  return compression.filter(req, res);
};

app.use(cors());

app.use(
  compression({
    filter: compressionFilter,
  }),
);

app.use(
  express.json({
    limit: "10mb",
    verify(req, _res, buf) {
      if (buf.length > 0) {
        req.rawBody = buf;
      }
    },
  }),
);

app.use(
  express.urlencoded({
    extended: true,
  }),
);

app.get("/product", (_req: Request, res: Response) => {
  res.json({
    ok: true,
  });
});

const server = http.createServer(app);

server.listen(port, () => {
  console.info(`Server started at port ${port}`);
});

src/types/express.d.ts

ts
declare global {
  namespace Express {
    interface Request {
      rawBody?: Buffer;
    }
  }
}

export {};

package.json

{
  "scripts": {
    "dev": "node --env-file=.env --import tsx src/server.ts",
    "build": "tsc",
    "start": "node dist/server.js"
  }
}

ESBuild

esbuild src/some.ts --bundle --minify --sourcemap --platform=node --target=es2022 --outfile=dist/index.js

tsconfig.base.json

json
{
  "compilerOptions": {
    /* Language and Environment */
    "target": "ESNext",                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */

    /* Modules */
    "module": "ES2022",                                  /* Specify what module code is generated. */
    // "rootDir": "./src",                                  /* Specify the root folder within your source files. */

    "moduleResolution": "node",                          /* Specify how TypeScript looks up a file from a given module specifier. */
    // "baseUrl": "./src",                                  /* Specify the base directory to resolve non-relative module names. */
    /* "paths": {
      "*": ["./*"]
    },*/                                                   /* Specify a set of entries that re-map imports to additional lookup locations. */
    // "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */
    // "typeRoots": [],                                  /* Specify multiple folders that act like './node_modules/@types'. */
    // "types": [],                                      /* Specify type package names to be included without being referenced in a source file. */

    /* Emit */

    // "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
    // "declarationMap": true,                           /* Create sourcemaps for d.ts files. */

    // "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
    // "sourceMap": true,                                /* Create source map files for emitted JavaScript files. */
    // "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
    // "outDir": "./dist",                                  /* Specify an output folder for all emitted files. */


    /* Interop Constraints */
    "esModuleInterop": true,                             /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports'    for type compatibility. */

    // "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
    "forceConsistentCasingInFileNames": true,            /* Ensure that casing is correct in imports. */

    /* Type Checking */
    "strict": true,                                      /* Enable all strict type-checking options. */
    "skipLibCheck": true                                 /* Skip type checking all .d.ts files. */
  }
}

tsconfig.json

json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "rootDir": "./src",
    "baseUrl": "./src",                                   /* Specify the base directory to resolve non-relative module names. */
    "paths": {
        "*": ["./*"]
      },
    "outDir": "./dist",
    "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
    "declarationMap": true,                           /* Create sourcemaps for d.ts files. */

    //"emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
    "sourceMap": true                                /* Create source map files for emitted JavaScript files. */
  }
}

eslint.custom.mjs

js
export default {
  rules: {
    indent: [
      "error",
      2,
      { "SwitchCase": 1}
    ],
    quotes: [
      "error",
      "single"
    ],
    "semi": [
      "error",
      "always"
    ],
    "space-before-blocks": [
      "error",
      "always"
    ],
    "space-before-function-paren": ["error", {
      "anonymous": "never",
      "named": "never",
      "asyncArrow": "always"
    }],
    "space-infix-ops": ["error", { "int32Hint": false }],
    "no-console": ["warn", { "allow": ["warn", "error"] }],
    "no-multiple-empty-lines": ["error", { "max": 1, "maxBOF": 0, "maxEOF": 1}],
    "no-duplicate-case": "error",
    "keyword-spacing": ["error", {
      "before": true,
      "after": true,
      "overrides": {
        "switch": {
          "after": false
        }
      }
    }],
    "no-unused-vars": "off",
    "@typescript-eslint/no-unused-vars": ["warn", {
      "argsIgnorePattern": "^_",
      "ignoreRestSiblings": true
    }]
  }
};

eslint.config.mjs

js
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
import config from "../../eslint.custom.mjs";

/** @type {import('eslint').Linter.Config[]} */
export default [
  {files: ["**/*.{js,mjs,cjs,ts}"]},
  {languageOptions: { globals: {...globals.browser, ...globals.node} }},
  pluginJs.configs.recommended,
  ...tseslint.configs.recommended,
  {
     ignores: ["eslint.config.*"]
  },
  {
    ... config
  }
];

Libraries