Comprehensive Node.js ESLint configuration with TypeScript/JavaScript support, security rules, and backend-specific optimizations. Built on @noneforge/eslint-config ESLint 9+ flat config with strict type checking and Node.js best practices.
- β¨ ESLint 9 Flat Config - Modern configuration format with better performance
- π― Node.js Optimized - Specific rules for backend development and server applications
- π Security First - Built-in security scanning with eslint-plugin-security
- β‘ Performance Rules - Async/promise optimization and Node.js performance patterns
- π¦ Full TypeScript Support - Extends @noneforge/eslint-config base with Node.js specifics
- π Node.js 20+ LTS - Targets modern Node.js features and APIs
- π§ Smart Detection - Different rules for tests, scripts, migrations, and configs
- @noneforge/eslint-config - TypeScript/Javascript base configuration
- @noneforge/eslint-config-angular - Angular application configuration
- Node.js >=20.0.0 (LTS)
- ESLint >=9.22.0
- TypeScript >=5.5.0
npm install --save-dev @noneforge/eslint-config-node eslint typescript
or with Yarn:
yarn add --dev @noneforge/eslint-config-node eslint typescript
Create an eslint.config.js
file in your project root:
import config from '@noneforge/eslint-config-node';
export default [
...config,
// Your custom rules here
];
import config from '@noneforge/eslint-config-node';
export default [
...config,
{
rules: {
// Override or add custom rules
'n/no-process-env': 'off',
'security/detect-child-process': 'off',
}
}
];
import config from '@noneforge/eslint-config-node';
export default [
...config,
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
project: ['./packages/*/tsconfig.json'],
}
}
}
];
Essential Node.js-specific error prevention and best practices:
- Import Protocol:
prefer-node-protocol
- Enforcesnode:
prefix for built-in modules - Module System: Prevents missing/extraneous imports and requires
- API Safety:
no-deprecated-api
- Warns about deprecated Node.js APIs - Process Control:
no-process-exit
,no-process-env
- Controlled process management - Sync Operations:
no-sync
- Prevents blocking I/O operations (configurable for scripts) - Promise APIs:
prefer-promises/fs
,prefer-promises/dns
- Modern async patterns
// β Old patterns
import fs from 'fs';
const data = fs.readFileSync('./file.txt');
process.exit(1);
// β
Modern Node.js patterns
import fs from 'node:fs/promises';
const data = await fs.readFile('./file.txt');
throw new Error('Exit with error');
Comprehensive security scanning for backend applications:
- Code Injection:
detect-eval-with-expression
,detect-non-literal-require
- File System:
detect-non-literal-fs-filename
- Prevents path traversal - Child Process:
detect-child-process
- Warns about shell execution - Regular Expressions:
detect-unsafe-regex
- Prevents ReDoS attacks - Cryptography:
detect-pseudoRandomBytes
- Ensures secure random generation - Buffer Safety:
detect-buffer-noassert
,detect-new-buffer
- Safe buffer usage
// β Security issues
const file = await fs.readFile(userInput); // Path traversal risk
const cmd = exec(`ls ${userDir}`); // Command injection
const regex = /^(a+)+$/; // ReDoS vulnerability
// β
Secure patterns
const file = await fs.readFile(path.join(SAFE_DIR, sanitize(userInput)));
const cmd = execFile('ls', [userDir]); // No shell interpolation
const regex = /^a+$/; // Linear time complexity
Advanced async/await patterns for Node.js:
- Error Handling:
catch-or-return
- All promises must be handled - Promise Creation:
no-new-statics
,no-return-wrap
- Correct promise patterns - Callback Integration:
no-callback-in-promise
,no-promise-in-callback
- Flow Control:
no-nesting
- Prevents deep promise chains - Return Patterns:
no-return-in-finally
- Ensures proper cleanup
// β Common async mistakes
async function fetchData() {
return new Promise.resolve(data); // Wrong promise creation
promise.then(handleSuccess, handleError); // Missing return
}
// β
Proper async patterns
async function fetchData() {
return data; // Implicit promise wrapping
return promise
.then(handleSuccess)
.catch(handleError); // Proper chaining
}
Modern JavaScript patterns optimized for Node.js:
- Top-Level Await:
prefer-top-level-await
- Modern module patterns - Array Methods:
prefer-at
,prefer-array-some
,no-array-push-push
- Modern APIs:
prefer-modern-math-apis
,prefer-structured-clone
- String Operations:
prefer-string-replace-all
- Efficient string handling - Collections:
prefer-set-has
- O(1) lookups over arrays - Optional Parameters:
prefer-default-parameters
,prefer-optional-catch-binding
// β Legacy patterns
const last = array[array.length - 1];
const copy = JSON.parse(JSON.stringify(obj));
str.replace(/foo/g, 'bar');
arr.includes(value); // O(n) for large arrays
// β
Modern patterns
const last = array.at(-1);
const copy = structuredClone(obj);
str.replaceAll('foo', 'bar');
set.has(value); // O(1) lookup
Relaxed rules for testing:
- Import restrictions lifted for test dependencies
- Security rules relaxed for test scenarios
- File system operations allowed for fixtures
Practical rules for tooling:
- Console output allowed
- Process environment access permitted
- Synchronous operations allowed
- Process exit allowed for CLI tools
Flexible configuration handling:
- Unpublished imports allowed
- Environment variables permitted
- Synchronous operations for config loading
- Dynamic requires for conditional configs
This package extends @noneforge/eslint-config which provides:
- Comprehensive TypeScript type checking
- Built-in formatting (Prettier replacement)
- Import organization and sorting
- Modern JavaScript best practices
- JSDoc documentation rules
See the base configuration README for details on inherited rules.
// β Direct process.env access (error by default)
const port = process.env.PORT;
// β
Centralized config with validation
// config.ts - use n/no-process-env override
export const config = {
port: process.env.PORT ? parseInt(process.env.PORT, 10) : 3000,
nodeEnv: process.env.NODE_ENV || 'development',
};
// Other files
import { config } from './config';
const port = config.port;
// β Synchronous operations block event loop
import fs from 'fs';
const data = fs.readFileSync('./data.json');
// β
Async operations with promises
import fs from 'node:fs/promises';
const data = await fs.readFile('./data.json', 'utf-8');
// β Unhandled promises and poor error flow
async function risky() {
doAsyncWork(); // Floating promise
process.exit(1); // Abrupt termination
}
// β
Proper error handling
async function safe() {
await doAsyncWork(); // Awaited
throw new Error('Descriptive error'); // Proper error flow
}
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:debug": "eslint . --debug",
"type-check": "tsc --noEmit"
}
}
- Remove
.eslintrc.*
files - Create
eslint.config.js
with flat config - Update VSCode settings for flat config
- Install this package and its peer dependencies
- Update scripts to use ESLint 9 CLI
- Use
projectService: true
for better TypeScript performance - Enable ESLint cache:
eslint . --cache
- Exclude
node_modules
anddist
in your tsconfig.json - Consider
--max-warnings 0
in CI/CD pipelines
This configuration prioritizes:
- Security - Prevent vulnerabilities in backend applications
- Performance - Non-blocking operations and efficient patterns
- Type Safety - Leverage TypeScript for runtime error prevention
- Modern APIs - Use latest Node.js features and best practices
- Developer Experience - Clear errors with practical escape hatches
MIT
Issues and PRs welcome at GitHub