Presets
The three presets and the resource-rules plugin, what each adds, and how to choose.
@workspace/eslint-config 2.2.0Developmentunreleased, in development in Foundationbaseline ce081dc3
The package exports four subpaths, exactly those of its exports map. Everything else in it
(react-rules.js, rules/) is internal and reached only through these.
| Import | Export | For |
|---|---|---|
@workspace/ | config, test | code without React or a browser: server code, tooling, types, data packages |
@workspace/ | config | a React component or hook library, used from source |
@workspace/ | next | a Next.js application |
@workspace/ | resource, resource | an addition to a preset, for code that queries a resource data layer |
Note the forms: the Next.js subpath is next-js and exports nextJsConfig, not config.
How they build on each other#
Both React presets start with everything in base, so a rule of base applies in every preset.
| Adds | base | react- | next- |
|---|---|---|---|
| JavaScript and TypeScript recommended rules | yes | yes | yes |
| Prettier compatibility, the Turbo rule, the project conventions | yes | yes | yes |
Node globals for every . file | yes | yes | yes |
| JSX parsing | no | yes | yes |
| browser globals | no | yes | no |
| service worker globals | no | yes | yes |
curated @eslint- rules and the rules of hooks | no | yes | yes |
| Next.js rules | no | no | yes |
| ignores | dist/ | dist/ | dist/, ., out/, build/, next- |
The difference in globals is small in practice: for TypeScript files typescript-eslint switches
no-undef off, because the compiler checks names itself. Globals matter for plain .js and .mjs
files.
Choosing a preset#
Choose by the package's own source files: ESLint lints only what lies in the workspace, not its dependencies.
| The package or app | Preset |
|---|---|
| a Next.js application | next- |
contains ., React components or hooks | react- |
| a React application without Next (for example Vite) | react- |
| anything else | base |
This is the opposite of the TypeScript choice, where what the type-check reaches through
dependencies decides. A package without React of its own can need react-library.json for
TypeScript and still use base here; see typescript-config.
Examples#
A React library:
// eslint.config.mjsimport {config} from '@workspace/eslint-config/react-internal';
/** @type {import("eslint").Linter.Config[]} */export default [ ...config, { ignores: ['node_modules/**', 'dist/**'], },];A Next.js application. The framework's build output is ignored by the preset; list your own generated folders:
// eslint.config.mjsimport {nextJsConfig} from '@workspace/eslint-config/next-js';
/** @type {import("eslint").Linter.Config[]} */export default [ ...nextJsConfig, { ignores: ['node_modules/**', 'test-results/**', 'playwright-report/**'], },];The React rules read the installed React version from the workspace where lint runs, so a React
library or app declares react itself.
The resource rules#
resource-rules is not a preset but an addition, for a repository with a data layer it is meant
for. Its two rules ask that every Prisma findMany and findFirst passes an explicit select,
and forbid spreading a caller's where fragment into a query. The rules name nothing of a
particular project; you decide which files form your resource layer:
// eslint.config.mjsimport {config} from '@workspace/eslint-config/base';import {resourceRulesConfig} from '@workspace/eslint-config/resource-rules';
/** @type {import("eslint").Linter.Config[]} */export default [ ...config, resourceRulesConfig(['src/resources/**/*.{ts,tsx}']),];Without a list of files the block applies wherever the surrounding configuration does. Like every rule here, both report warnings. A library repository does not use them.