Linting & Formatting Best Practices
A condensed summary of the 25 most important best practices drawn from every page in this section.
Search across all documentation pages
A condensed summary of the 25 most important best practices drawn from every page in this section.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
eslint.config.mjs and delete every leftover .eslintrc.* file, because ESLint falls back to the legacy format if both exist and your flat config is silently ignored.extends-style configs, so wrap them with FlatCompat({ baseDirectory: __dirname }) and recreate __dirname via fileURLToPath(import.meta.url) in ESM.{ ignores: [...] } only acts as a global ignore when it is the sole key in its object; mixing it with rules turns it into a per-file filter.eslint-plugin-react, react-hooks, next, import, and jsx-a11y, so you rarely need to install those plugins separately and can layer only what is missing."error" for rules you want to enforce (fail CI, block builds) and reserve "warn" for rules you are migrating toward, since warnings pass CI and silently accumulate.no-unused-vars off and enable @typescript-eslint/no-unused-vars with argsIgnorePattern: "^_" so interface/type-alias/enum syntax is understood and conflicts disappear.import type { … } for type-only imports so bundlers can fully erase types and your type graph stays clearly separated from your value graph.react-hooks/exhaustive-deps on (usually as "warn") and suppress it per-line with // eslint-disable-next-line only for provably stable references like dispatch or refs.import/order with grouped categories (builtin, external, internal, parent/sibling, index, type), "newlines-between": "always", and alphabetization; run eslint --fix once and add any missing blank lines by hand.next/core-web-vitals already includes (react, react-hooks, next, import, jsx-a11y) causes duplicate registration and unexpected rule behavior, so check the preset first.eslint-plugin-testing-library behind files: ["**/*.test.{ts,tsx}", "**/*.spec.{ts,tsx}"]; applied globally it produces false positives on non-test code.TIMING=1 npx eslint . when lint times creep up - five or more active plugins can meaningfully slow linting, and type-aware @typescript-eslint rules are 2-5x slower because they require full type info."prettier" entry must be the final item in your extends array, because it only turns off formatting rules and any config listed after it will re-enable conflicts..next/, node_modules/, lock files, and generated code; an explicit ignore file keeps runs fast and prevents unintended changes.prettier-plugin-tailwindcss must sit at the end of the Prettier plugins array or it will conflict with other Prettier plugins and class sorting breaks."endOfLine": "lf" in .prettierrc and configure git config --global core.autocrlf input so Windows contributors do not ship CRLF files that fail prettier --check on Linux CI..vscode/settings.json and .vscode/extensions.json (not launch.json or *.code-workspace) so every developer inherits the same format-on-save, ESLint, and recommended-extensions behavior.editor.defaultFormatter both globally and per language ([typescript], [typescriptreact], [json]) to avoid VS Code picking a random formatter when multiple are installed.typescript.tsdk at node_modules/typescript/lib so editor type-checking matches the version tsc uses in CI, eliminating "works on my machine" type drift."strict": true for the eight bundled checks and add noUncheckedIndexedAccess, noImplicitReturns, noFallthroughCasesInSwitch, and verbatimModuleSyntax because they are not included in strict."strict": false and enable strictNullChecks first, then noImplicitAny, using // @ts-expect-error (not @ts-ignore) so suppressions auto-fail once the underlying issue is fixed."type-check": "tsc --noEmit" and rely on incremental: true plus a cached .tsbuildinfo for speed."prepare": "husky" in package.json so pre-commit hooks are installed automatically after npm install, and keep hooks fast by running only lint-staged (with eslint --fix --no-warn-ignored) - never full tsc.prettier --check, and tsc --noEmit in GitHub Actions using npm ci for deterministic installs, a matching pinned Node version, a concurrency group with cancel-in-progress: true, and branch-protection rules that require the job to pass before merge.Reviewed by Chris St. John·Last updated Jul 16, 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥