Configuration
Flags
| Flag | Default | What it does |
|---|---|---|
react | false | React 19+ with Server Components, Hooks, JSX-A11y, Storybook, Testing Library |
node | false | Node.js globals, eslint-plugin-n rules. Disables browser compat checks. In mixed frontend/backend repos, add file-scoped overrides (see below). |
ai | false | Enforces a consistent standard across human and AI contributors (see AI Mode) |
oxlint | false | Disables ESLint rules that OxLint already covers (see OxLint Integration) |
Flags are independent. Combine them however you need. 2^4 = 16 configs exist, all pre-built.
NOTE
TypeScript always uses strictTypeChecked — the strictest typescript-eslint preset. No "recommended" fallback. This matches TypeScript's own direction toward strict-by-default.
Usage examples
// eslint.config.ts
import { getEslintConfig } from "eslint-config-setup"
export default await getEslintConfig({ react: true })Mixed frontend/backend repositories
When you enable both react: true and node: true, environment-specific rules and globals are loaded into the shared generated config. This is intentional for the pre-built 16-permutation architecture.
Option A: directory-local configs (recommended)
For strict runtime boundaries, use directory-local eslint.config.* files and let ESLint resolve them per file:
project/
├── eslint.config.ts # root/scripts config
├── app/
│ └── eslint.config.ts # react config
└── convex/
├── package.json # engines.node for backend runtime
└── eslint.config.ts # node config// eslint.config.ts (root)
import { getEslintConfig } from "eslint-config-setup"
export default await getEslintConfig({
node: true,
})// app/eslint.config.ts
import { getEslintConfig } from "eslint-config-setup"
export default await getEslintConfig({
ai: true,
react: true,
})// convex/eslint.config.ts
import { getEslintConfig } from "eslint-config-setup"
export default await getEslintConfig({
ai: true,
node: true,
})// convex/package.json
{
"name": "convex-backend",
"private": true,
"engines": {
"node": ">=22.4.0"
}
}Run lint from the repo root:
# ESLint 10 (default)
eslint .
# ESLint 9.30+ (enable per-file config lookup)
eslint --flag v10_config_lookup_from_file .No root: true setting is needed with flat config.
For older ESLint 9 releases, use --flag unstable_config_lookup_from_file or separate --config scripts.
eslint-plugin-n resolves the Node target from engines.node by default. Prefer this over per-rule overrides.
Option B: single config + file-scoped overrides
If you prefer one config file, add explicit file-scoped blocks:
// package.json
{
"engines": {
"node": ">=22.4.0"
}
}// eslint.config.ts
import { getEslintConfig } from "eslint-config-setup"
const config = await getEslintConfig({
ai: true,
react: true,
node: true,
})
config.push(
{
name: "project/browser-runtime",
files: ["app/**/*.{ts,tsx}"],
languageOptions: {
globals: {
// Disable leaked Node globals in browser code
Buffer: "off",
__dirname: "off",
__filename: "off",
module: "off",
process: "off",
require: "off",
},
},
rules: {
"node/no-unsupported-features/node-builtins": "off",
},
},
{
name: "project/node-runtime",
files: ["convex/**/*.ts", "scripts/**/*.ts"],
languageOptions: {
globals: {
// Disable leaked browser globals in server code
document: "off",
localStorage: "off",
navigator: "off",
sessionStorage: "off",
window: "off",
},
},
},
)
export default configThis keeps the generated baseline, while making runtime boundaries explicit in your project.
TIP
See the Rule API for the full set of rule manipulation functions and scoped rules.