Appearance
ESLint how-to
Lint a Next.js app with ESLint 9 flat config.
Install
bash
pnpm add -D eslint eslint-config-next eslint-config-prettier
pnpm install # if the monorepo already lists them| Package | Role |
|---|---|
eslint | CLI + engine |
eslint-config-next | Next core-web-vitals + TypeScript recommended |
eslint-config-prettier | Turns off rules that fight Prettier |
Config file: eslint.config.mjs (flat config).
Commands
bash
pnpm run lint
pnpm run lint:fix
pnpm exec eslint path/to/file.tsxImplementation examples
Flat config shape
js
// eslint.config.mjs
import { defineConfig, globalIgnores } from 'eslint/config';
import nextVitals from 'eslint-config-next/core-web-vitals';
import nextTs from 'eslint-config-next/typescript';
import prettier from 'eslint-config-prettier/flat';
export default defineConfig([
...nextVitals,
...nextTs,
prettier,
{
rules: {
'no-console': 'error',
'@typescript-eslint/no-explicit-any': ['error', { fixToUnknown: true }],
'max-params': ['warn', { max: 3 }],
complexity: ['warn', { max: 10 }],
'max-lines': ['warn', { max: 250, skipBlankLines: true, skipComments: true }],
},
},
{
files: ['scripts/**/*.{js,mjs,cjs,ts}'],
rules: { 'no-console': 'off' },
},
globalIgnores(['.next/**', 'studio/**', '**/.vitepress/dist/**']),
]);Fixing common findings
ts
// Bad
console.log('debug');
function load(a: any) {
return a;
}
// Good
function load(a: unknown) {
if (typeof a !== 'string') throw new Error('expected string');
return a;
}ts
// Prefer options objects over long parameter lists
function send(options: { to: string; from: string; subject: string; body: string }) {}Not covered by ESLint
- Types → TypeScript
- Dead modules → Fallow
- Formatting → Prettier