eslint-config-reactify
v2.0.1
Published
ESLint 10 flat config for React, Next.js, and Node.js — bundled plugins, zero setup
Readme
eslint-config-reactify
A comprehensive ESLint configuration for React, Node.js, and Next.js TypeScript projects.
ESLint 10 flat config only — pick /react, /node, or /next for your stack.
✨ Features
- ✅ ESLint 10 flat config (
eslint.config.js) - ✅ Pre-configured for React, TypeScript, JSX, imports, tests, and more
- ✅ Optional JSDoc and TSDoc extras (
/extra/jsdoc,/extra/tsdoc) - ✅ Opinionated formatting via
@stylistic/eslint-plugin - ✅ Linting for test files, config files, JSON, and imports
- ✅ Includes rules from 15+ ESLint plugins
Requirements
- Node.js
>=20.19.0(or>=22.13.0, or>=24.0.0) — ESLint 10 requirement - ESLint
^10.0.0
📦 Installation
npm install -D eslint@^10 eslint-config-reactify
# or
yarn add -D eslint@^10 eslint-config-reactify
# or
pnpm add -D eslint@^10 eslint-config-reactifyOnly
eslintis required as a peer dependency. All plugins are bundled.
🚀 Usage
Flat Config
Import the config that matches your stack:
| Entry | Use for |
|-------|---------|
| eslint-config-reactify/react | React + TypeScript |
| eslint-config-reactify/node | Node.js (no React) |
| eslint-config-reactify/next | Next.js |
// eslint.config.mjs
import config from 'eslint-config-reactify/react';
export default [
...config
// Other configs
];Optional extras
Documentation plugins are not included in the main configs. Add them when you want JSDoc/TSDoc linting:
| Entry | Use for |
|-------|---------|
| eslint-config-reactify/extra/jsdoc | JSDoc comments on JS/TS files |
| eslint-config-reactify/extra/tsdoc | TSDoc syntax on TypeScript files |
// eslint.config.mjs
import config from 'eslint-config-reactify/react';
import jsdoc from 'eslint-config-reactify/extra/jsdoc';
import tsdoc from 'eslint-config-reactify/extra/tsdoc';
export default [
...config,
...jsdoc,
...tsdoc,
];Next.js (eslint-config-next)
ESLint 10 flat config allows each plugin ID (for example import, react, react-hooks, @typescript-eslint) to be registered only once in the merged config. eslint-config-next and eslint-config-reactify both attach those plugins, which triggers Cannot redefine plugin … in the VS Code ESLint extension if you spread both configs verbatim.
Spread Next’s config first, then map every reactify slice through a small helper that drops only the plugin entries Next already owns. Rules, settings, and other plugins (for example @stylistic, perfectionist, json) stay on the slice, so behavior stays the same aside from sharing Next’s plugin instances.
npm install -D eslint@^10 eslint-config-next eslint-config-reactify
# or
yarn add -D eslint@^10 eslint-config-next eslint-config-reactify
# or
pnpm add -D eslint@^10 eslint-config-next eslint-config-reactifyUse the eslint-config-reactify/next entry. It layers the default Next flat setup (core-web-vitals, typescript, globalIgnores) and then reactify with duplicate plugins stripped so ESLint does not throw Cannot redefine plugin ….
Note: Some transitive dependencies of
eslint-config-next(for exampleeslint-plugin-react) may still declare ESLint 9 peer ranges until upstream releases ESLint 10 support. If install fails on peer deps, use your package manager’s legacy-peer-deps option or track vercel/next.js#91702.
// eslint.config.mjs
import config from 'eslint-config-reactify/next';
export default config;Add your own config objects after importing if you need overrides.
Node.js (TypeScript / JavaScript)
For server-side projects without React, use eslint-config-reactify/node. It shares the same stylistic, import, and TypeScript conventions as the React config but omits React, JSX, TanStack Router/Query, and jest-dom. Add /extra/jsdoc and /extra/tsdoc separately if you want documentation linting.
// eslint.config.mjs
import config from 'eslint-config-reactify/node';
export default [...config];Migrating to v2 (ESLint 10)
This release requires ESLint 10 and Node.js >=20.19.0. See the official ESLint 10 migration guide.
Breaking changes
- ESLint 10 only — peer dependency is
eslint@^10.0.0 - No
.eslintrcsupport — ESLint 10 removed the legacy config format; the/legacyentry was removed - Explicit subpath imports only — use
eslint-config-reactify/react,/node, or/next(no bare package import) - JSDoc/TSDoc optional — no longer in main configs; import
/extra/jsdocand/extra/tsdocif needed - Node.js — v20.19+, v22.13+, or v24+ required
What you may notice after upgrading
- New
eslint:recommendedrules:no-unassigned-vars,no-useless-assignment,preserve-caught-error - JSX identifiers are now tracked as references (fewer false
no-unused-varsreports in React code) /* eslint-env */comments are errors — remove them from your codebase- Config lookup starts from each linted file’s directory (ESLint 10 default)
- Some bundled plugins still declare ESLint 9 peer ranges; this package uses
@eslint/compatshims until upstream releases catch up
🔧 Overriding Rules
In eslint.config.js:
import config from 'eslint-config-reactify/react';
export default [
...config,
{
rules: {
'no-console': 'warn',
},
},
];📁 Ignored by Default
These folders and files are excluded:
dist, build, coverage, node_modules, public, out, storybook-static, .next, .turbo, .cache, turbo.json📚 Rules Included
🧠 Core Logic & Styling — @stylistic/eslint-plugin
@stylistic/semi: require semicolons@stylistic/quotes: enforce single quotes@stylistic/indent: 4-space indentation@stylistic/comma-dangle: trailing commas for multiline@stylistic/max-len: 256 character line limit@stylistic/no-extra-semi: disallow extra semicolons@stylistic/lines-between-class-members: spacing in classes@stylistic/type-named-tuple-spacing: spacing in tuples- and more...
💡 React — eslint-plugin-react, react-hooks, react-refresh
react/jsx-key: enforce keys in listsreact/button-has-type: requiretypeon<button>react/jsx-sort-props: consistent prop orderreact/jsx-tag-spacing: spacing in tagsreact/self-closing-comp: enforce self-closing tagsreact/function-component-definition: enforce arrow componentsreact-refresh/only-export-components: safe HMR boundaries- and more...
⚙️ TypeScript — @typescript-eslint/eslint-plugin
@typescript-eslint/consistent-type-imports: Enforces consistent type import style with inline type imports preference@typescript-eslint/no-empty-object-type: off@typescript-eslint/no-explicit-any: off (explicit any allowed)@typescript-eslint/no-non-null-assertion: off (relaxed)@typescript-eslint/no-unnecessary-condition: off@typescript-eslint/prefer-nullish-coalescing: off@typescript-eslint/sort-type-constituents: off (custom sorting used)- and more...
📦 Import Handling — eslint-plugin-import, simple-import-sort, import-newlines
import/consistent-type-specifier-style: offimport/exports-last: offimport/extensions: offimport/group-exports: offimport/namespace: enforce import syntax (with computed allowed)import/newline-after-import: enforce newline after importimport/no-default-export: offimport/no-duplicates: disallow duplicate importsimport/no-extraneous-dependencies: offimport/no-named-as-default: offimport/no-unresolved: offimport-newlines/enforce: enforce newlines in import lists (30 items, max-len 240)simple-import-sort/exports: warnsimple-import-sort/imports: warn
📚 Documentation (optional extras)
Import separately — not included in /react, /node, or /next:
eslint-config-reactify/extra/jsdoc—jsdoc/require-description,jsdoc/require-throws, and related JSDoc ruleseslint-config-reactify/extra/tsdoc—tsdoc/syntaxfor TypeScript files
🔬 Code Quality — sonarjs, perfectionist, no-secrets
sonarjs/...: complexity, duplication, etc.no-secrets/no-secrets: detect secrets in codeperfectionist/sort-exports: sorted exports with comment partitioningperfectionist/sort-imports: off (we usesimple-import-sort)perfectionist/sort-jsx-props: off (covered byreact/jsx-sort-props)perfectionist/sort-modules: sorted modules with comment partitioningperfectionist/sort-union-types: sorted union types (custom groups)
🧪 Test Files — eslint-plugin-jest & eslint-plugin-jest-dom
Applied to test/**, **/*.test.{js,jsx,ts,tsx}, and **/*.spec.{js,jsx,ts,tsx} and includes:
jest-dom/...: recommended DOM testing rulesjest/...: recommended Jest rules
🔧 Misc
*.json: enabled witheslint-plugin-jsonsrc/pages/**/*.tsx: relaxed React rules for Next.js-style routes (i.e, Tanstack Router)src/types/*.ts&src/stores/*.ts: relaxed export rules.cz-config.cjs,jest.setup.ts,postcss.config.js: relaxed for CommonJS usage
✅ Example Project Setup
npm install -D eslint@^10 eslint-config-reactify
# or
yarn add -D eslint@^10 eslint-config-reactify
# or
pnpm add -D eslint@^10 eslint-config-reactifyCreate eslint.config.js:
import config from 'eslint-config-reactify/react';
export default [...config];Optional: add eslint-config-reactify/extra/jsdoc and /extra/tsdoc for documentation rules (see Optional extras).
Add a lint script:
{
"scripts": {
"lint": "eslint . --report-unused-disable-directives --max-warnings 0 --no-warn-ignored --fix"
}
}Then run npm run lint, yarn lint, or pnpm run lint.
🤖 Train Cursor & AI Agents (save tokens)
AI agents (Cursor, Copilot, Claude Code, etc.) start every session with no memory of your project. Left alone, they re-explore the repo, re-read eslint.config.mjs, and re-derive your conventions each time — burning tokens and sometimes guessing wrong.
You can "train" them once by committing a small context file that they read automatically. This is the same idea as this package: centralize conventions so nobody (human or agent) rediscovers them.
How it saves tokens
- No repeated exploration — the agent reads one short file instead of scanning many source files.
- Fewer wrong guesses — it knows up front: flat config only, no Prettier, arrow components,
/nextfor Next.js, etc. - Smaller prompts — a ~1 screen cheat sheet replaces thousands of tokens of file reads per session.
Setup
This package ships copy-paste templates under templates/:
| File | Where it goes |
|------|---------------|
| templates/AGENTS.md | Your app repo root (AGENTS.md) — read by most agents |
| templates/cursor-rule-reactify.mdc | .cursor/rules/ — auto-loaded by Cursor |
- Copy
templates/AGENTS.mdto your repo root and adjust paths/stack. - Copy
templates/cursor-rule-reactify.mdcto.cursor/rules/for Cursor to load it every session. - Commit both so the whole team (and their agents) inherit the same context.
Other tools read the same content under different names — Copilot uses .github/copilot-instructions.md, Claude Code uses CLAUDE.md. Point them at the same conventions.
The key rule to give agents: don't re-read the repo to infer style — AGENTS.md + eslint.config.mjs are authoritative, run lint instead of guessing.
📄 License
MIT © hamidyfine
