Coding Standards
Coding standards for Node.js + TypeScript teams: enforceable in ESLint and CI, not a wiki nobody reads. Aligns with Code Review Standards.
Search across all documentation pages
Coding standards for Node.js + TypeScript teams: enforceable in ESLint and CI, not a wiki nobody reads. Aligns with Code Review Standards.
Quick-reference recipe card.
// package.json
{
"type": "module",
"scripts": {
"lint": "eslint . && prettier --check .",
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"@acme/eslint-config": "^3.0.0",
"typescript": "^5.6.0"
}
}// eslint.config.js (flat config)
import acme from "@acme/eslint-config/node-service";
export default [...acme];Non-negotiable rules:
@typescript-eslint/no-floating-promises: error@typescript-eslint/no-misused-promises: errorno-console: warn (use structured logger)import/no-cycle: errorprettier/prettier: error// packages/eslint-config/node-service.js
import tseslint from "typescript-eslint";
import prettier from "eslint-config-prettier";
export default tseslint.config(
...tseslint.configs.strictTypeChecked,
{
rules: {
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/require-await": "off",
"no-restricted-imports": ["error", {
patterns: [{ group: ["../**/infrastructure/**"], message: "Use application ports" }],
}],
},
},
prettier,
);{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"noUncheckedIndexedAccess": true,
"skipLibCheck": true
}
}// .dependency-cruiser.cjs
module.exports = {
forbidden: [
{
name: "no-infra-in-domain",
from: { path: "^src/modules/[^/]+/domain" },
to: { path: "express|fastify|@nestjs" },
},
],
};| Item | Convention |
|---|---|
| Files | kebab-case.ts |
| Types/interfaces | PascalCase |
| Functions/vars | camelCase |
| Env vars | SCREAMING_SNAKE |
| Test files | *.test.ts beside source |
// Prefer
export async function getUser(id: string): Promise<User | null> { ... }
// Avoid
export function getUser(id: string): Promise<User | null> {
return db.user.findUnique(...); // OK if eslint clean
}// Use child logger with context
req.log.info({ userId, orderId, msg: "order_created" });
// Never
console.log("order created", user.email);src/modules/orders/
domain/
application/
infrastructure/@acme/eslint-config semver.strict with incremental // @ts-expect-error budget decreasing quarterly.eslint-config-prettier last in array.main.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.
Reviewed by Chris St. John·Last updated Jul 16, 2026