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 typescript
or 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:fs
instead offs
- Promise-based APIs - Prefers
fs.promises
over 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 0
in 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.js
with flat config - Update to Node.js 20+ for full feature support
- Replace
eslint-plugin-node
witheslint-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