eslint
ESLint Flat Config with TypeScript
ESLint flat config (eslint.config.js) for TypeScript projects with recommended rules, import sorting, and React support.
Overview
ESLint’s flat config format (eslint.config.js) replaces the legacy .eslintrc files. This configuration sets up TypeScript-aware linting with recommended rules, import organization, and optional React support using the new flat config API.
Configuration
// eslint.config.js
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
import importPlugin from "eslint-plugin-import";
import prettierConfig from "eslint-config-prettier";
export default tseslint.config(
// ── Global Ignores ──
{
ignores: [
"dist/",
"build/",
"node_modules/",
"coverage/",
"*.config.js", // Don't lint config files
"**/*.d.ts", // Skip declaration files
],
},
// ── Base ESLint Recommended Rules ──
eslint.configs.recommended,
// ── TypeScript Recommended Rules ──
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.stylisticTypeChecked,
// ── TypeScript Parser Configuration ──
{
languageOptions: {
parserOptions: {
projectService: true, // Auto-detect tsconfig.json
tsconfigRootDir: import.meta.dirname,
},
},
},
// ── Import Organization ──
{
plugins: {
import: importPlugin,
},
rules: {
"import/order": [
"error",
{
groups: [
"builtin", // Node.js built-ins (fs, path)
"external", // npm packages
"internal", // Path aliases (@/*)
"parent", // Parent imports (../)
"sibling", // Same directory (./)
"index", // Index file (./)
],
"newlines-between": "always",
alphabetize: {
order: "asc",
caseInsensitive: true,
},
},
],
"import/no-duplicates": "error", // Merge imports from same module
},
},
// ── Custom Rules ──
{
rules: {
// TypeScript-specific
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_", // Allow _unused parameters
varsIgnorePattern: "^_", // Allow _unused variables
},
],
"@typescript-eslint/consistent-type-imports": [
"error",
{ prefer: "type-imports" }, // Enforce `import type { Foo }`
],
"@typescript-eslint/no-import-type-side-effects": "error",
"@typescript-eslint/no-floating-promises": "error", // Must await promises
"@typescript-eslint/no-misused-promises": "error", // No promises in void contexts
"@typescript-eslint/require-await": "error",
// General quality
"no-console": ["warn", { allow: ["warn", "error"] }], // Allow console.warn/error
"prefer-const": "error", // Use const when variable isn't reassigned
eqeqeq: ["error", "always"], // Require === instead of ==
curly: ["error", "all"], // Require braces for all blocks
},
},
// ── Prettier Compatibility (must be last) ──
prettierConfig,
);
Key Options Explained
tseslint.config()— Helper that provides proper typing and merging for flat config objects. Accepts spread arrays from preset configs.recommendedTypeChecked— Enables rules that use TypeScript’s type information for deeper analysis (e.g., detecting floating promises, type misuse).projectService: true— Automatically finds and uses the nearesttsconfig.jsonfor each file. Replaces the olderproject: trueoption.consistent-type-imports— Enforcesimport type { Foo }for type-only imports, enabling better tree-shaking and faster builds.argsIgnorePattern: "^_"— Allows unused function parameters prefixed with underscore, common for callbacks like(_req, res).eslint-config-prettier— Disables all ESLint rules that conflict with Prettier formatting. Must be the last config in the array.import/order— Enforces a consistent import ordering with automatic grouping and alphabetical sorting within groups.
Common Modifications
- Add React: Install
eslint-plugin-reactandeslint-plugin-react-hooks, then addreactPlugin.configs.flat.recommendedandreactHooksPlugin.configs['recommended-latest']to the config array. - Next.js: Use
@next/eslint-plugin-nextwithnextPlugin.configs['core-web-vitals']for Next.js-specific rules. - Disable type-checked rules: Replace
recommendedTypeCheckedwithrecommendedif type-aware linting is too slow for your project. - Allow console.log: Change
"no-console"to"off"in development or use environment-based configuration. - Custom path aliases: Add
settings: { "import/resolver": { typescript: true } }witheslint-import-resolver-typescriptfor path alias resolution.