Production-ready Node.js ESLint configuration with TypeScript, security rules, and performance optimizations. Built on top of @stackvault/eslint-config-typescript with Node.js-specific enhancements for backend development.
- 🛡️ Security First - Built-in security scanning with eslint-plugin-security
- 🚀 Node.js 20+ Optimized - Leverages modern Node.js APIs and patterns
- 📦 TypeScript Foundation - Inherits all strict type checking from base config
- ⚡ Performance Rules - Enforces async patterns and non-blocking operations
- 🔒 Promise Safety - Comprehensive promise and async/await validation
- 🎯 Modern Patterns - Prefers native Node.js APIs and ES2021+ features
npm install --save-dev @stackvault/eslint-config-node eslint typescriptor with Yarn:
yarn add --dev @stackvault/eslint-config-node eslint typescript- Node.js >=20.0.0 (LTS)
- ESLint >=9.22.0
- TypeScript >=5.5.0
Create an eslint.config.js file in your project root:
import nodeConfig from '@stackvault/eslint-config-node'; export default [ ...nodeConfig, // Your custom rules here ];import nodeConfig from '@stackvault/eslint-config-node'; export default [ ...nodeConfig, { rules: { // Override for your specific needs 'n/no-process-env': 'off', // If you need direct process.env access 'security/detect-object-injection': 'off', // If too many false positives } } ];import nodeConfig from '@stackvault/eslint-config-node'; export default [ ...nodeConfig, { rules: { 'n/no-process-exit': 'off', // Allow process.exit for containers 'n/no-sync': 'off', // Allow sync operations at startup } } ];This configuration extends @stackvault/eslint-config-typescript, providing:
- Strict type checking with type-aware rules
- Built-in formatting via @stylistic/eslint-plugin (no Prettier needed)
- Import sorting and organization
- Consistent code patterns and naming conventions
Comprehensive security scanning to prevent common vulnerabilities:
- Path traversal protection - Detects non-literal fs operations
- Command injection prevention - Flags dangerous child_process usage
- RegExp DoS protection - Identifies unsafe regular expressions
- Timing attack warnings - Alerts on potential timing vulnerabilities
- Buffer safety - Ensures secure buffer operations
Modern Node.js patterns enforced via eslint-plugin-n:
- Node: protocol imports - Requires
node:fsinstead offs - Promise-based APIs - Prefers
fs.promisesover callbacks - Version compatibility - Ensures Node.js 20+ API usage
- Global preferences - Enforces global Buffer, process, console
- No blocking operations - Prevents synchronous I/O in async contexts
Enhanced async operation rules via eslint-plugin-promise:
- Proper error handling - Enforces catch or return for promises
- Async/await patterns - Prefers modern async over callbacks
- Promise chain safety - Prevents common promise anti-patterns
- No floating promises - Ensures all promises are handled
Selected Unicorn rules for cleaner code:
- Modern APIs -
.at(),.replaceAll(), structured clone - Top-level await - For ES modules
- Prefer for...of - Over forEach for better performance
- Optional catch binding - Cleaner error handling
- Native fetch - Uses Node.js built-in fetch
// ❌ Error: detect-non-literal-fs-filename const file = userInput; fs.readFile(file, callback); // ✅ Correct: Validate and sanitize paths import path from 'node:path'; const safePath = path.join(SAFE_DIR, path.basename(userInput)); fs.readFile(safePath, callback);// ❌ Error: prefer-node-protocol import fs from 'fs'; import { readFile } from 'fs/promises'; // ✅ Correct: Use node: protocol import fs from 'node:fs'; import { readFile } from 'node:fs/promises';// ❌ Error: no-sync const data = fs.readFileSync('config.json'); // ✅ Correct: Use async operations const data = await fs.promises.readFile('config.json');// ❌ Error: no-floating-promises async function processData() { saveToDatabase(data); // Floating promise } // ✅ Correct: Handle the promise async function processData() { await saveToDatabase(data); // or void saveToDatabase(data); // Explicitly ignore }Relaxed rules for *.config.js and *.config.ts:
- Sync operations allowed
- Environment variables permitted
- Dynamic requires allowed
Relaxed security and type checking for *.spec.ts and *.test.ts:
- Unpublished imports allowed (for test libraries)
- Object injection warnings disabled
- Any types permitted for mocking
Special rules for scripts/ and migrations/ directories:
- Console logging allowed
- Process.exit permitted
- File system warnings reduced
Add to .vscode/settings.json:
{ "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" }, "eslint.experimental.useFlatConfig": true, "eslint.validate": [ "javascript", "typescript" ] }{ "scripts": { "lint": "eslint .", "lint:fix": "eslint . --fix", "lint:ci": "eslint . --max-warnings 0", "lint:security": "eslint . --rule 'security/*: error'", "type-check": "tsc --noEmit" } }For projects using environment variables:
// Create a typed env.ts file const env = { PORT: process.env.PORT || '3000', NODE_ENV: process.env.NODE_ENV || 'development', DATABASE_URL: process.env.DATABASE_URL!, } as const; export default env;This pattern provides type safety while satisfying linter rules.
- Enable ESLint cache:
eslint . --cache - Use
--max-warnings 0in CI/CD pipelines - Consider disabling expensive rules in development:
const isDev = process.env.NODE_ENV === 'development'; export default [ ...nodeConfig, { rules: { 'security/detect-object-injection': isDev ? 'off' : 'warn', } } ];
// Recommended error class class AppError extends Error { constructor( message: string, public statusCode: number = 500, public isOperational = true ) { super(message); Error.captureStackTrace(this, this.constructor); } }// Express async handler wrapper const asyncHandler = (fn: RequestHandler): RequestHandler => { return (req, res, next) => { Promise.resolve(fn(req, res, next)).catch(next); }; };- Remove
.eslintrc.*files - Create
eslint.config.jswith flat config - Update to Node.js 20+ for full feature support
- Replace
eslint-plugin-nodewitheslint-plugin-n - Update scripts to use flat config
This configuration prioritizes:
- Security - Prevent vulnerabilities before they reach production
- Performance - Non-blocking operations and modern APIs
- Type Safety - Full TypeScript benefits for backend code
- Modern Patterns - Leverage Node.js 20+ capabilities
- Developer Experience - Clear errors with actionable fixes
MIT
Issues and PRs welcome at GitHub