How to Configure ESlint with Nextjs in 3 Minutes
Clean your Nextjs App and Write Optimal Code
If you look for ESLint tutorials for Nextjs, you will either find configurations that are too strict, too lenient, and zero that are just right.
In this article, I will show you how to setup ESLint in 3 minutes, and provide the best ESLint configuration to help you write clean code faster, and ensure consistency throughout your application code.
So without further ado… Let’s dive right in!
Install Dependencies
For the best ESLint configuration, there are a lot of dependencies you need to install.
But don't be intimidated by this, the dependencies themselves aren't too large, and they are dev dependencies so they will not increase your app bundle size:
pnpm add @typescript-eslint/parser eslint eslint-config-airbnb eslint-config-airbnb-typescript eslint-config-next eslint-config-prettier eslint-plugin-import eslint-plugin-react eslint-plugin-prettier prettier eslint-plugin-jsx-a11y eslint-plugin-react-hooks eslint-plugin-simple-import-sort eslint-plugin-tailwindcss prettier-plugin-tailwindcss eslint-plugin-unused-imports -D
The ESLint Configuration
Before we create the configuration file, create a file called .eslintignore
and make sure to ignore the following directories from being linted:
node_modules
out
Now lets create the configuration file.
Create a file called .eslintrc.json
in the root of your Nextjs project and copy the following settings.
NOTE: I have added comments for each line to give a basic explanation of what each rule does.
{
// Base configuration for JavaScript files
"extends": [
"airbnb-base", // Airbnb's base JS style guide
"next/core-web-vitals", // Next.js core web vitals plugin to avoid build warnings
"plugin:prettier/recommended" // Integrates Prettier with ESLint
],
"rules": {
"prettier/prettier": [
"error",
{
"singleQuote": false, // Use single quotes instead of double quotes
"endOfLine": "auto", // Maintain consistent end of line behavior across environments
"semi": false // Omit semicolons at the end of statements
}
] // Prevent conflicts between Prettier and Airbnb ESLint rules
},
"settings": {
"tailwindcss": {
"callees": ["classnames", "clsx", "ctl", "cva", "tv", "cn"] // Tailwind utility class detection for specific libraries
}
},
"overrides": [
{
// Configuration specifically for TypeScript files
"files": ["**/*.ts", "**/*.tsx", "**/*.mts"], // Applies these rules only to TypeScript files
"plugins": [
"@typescript-eslint", // TypeScript specific linting rules
"unused-imports", // Plugin to automatically remove unused imports
"tailwindcss", // Tailwind CSS specific linting
"simple-import-sort" // Plugin to enforce consistent import order
],
"extends": [
"plugin:tailwindcss/recommended", // Recommended Tailwind CSS linting rules
"airbnb", // Airbnb's full style guide (JS + React)
"airbnb-typescript", // Airbnb's TypeScript style guide
"next/core-web-vitals", // Next.js core web vitals plugin
"plugin:prettier/recommended" // Integrates Prettier with ESLint
],
"parser": "@typescript-eslint/parser", // Uses TypeScript parser for ESLint
"parserOptions": {
"project": "./tsconfig.json" // Ensures TypeScript is linted according to the project's tsconfig.json
},
"rules": {
"prettier/prettier": [
"error",
{
"singleQuote": false, // Use double quotes for TypeScript files
"endOfLine": "auto", // Maintain consistent end of line behavior across environments
"semi": false, // Omit semicolons at the end of statements
"trailingComma": "es5" // Include trailing commas where valid in ES5
}
], // Prevent conflicts between Prettier and Airbnb ESLint rules
"tailwindcss/no-custom-classname": ["off"], // Allow custom class names (not restricted to Tailwind)
"import/no-extraneous-dependencies": "warn", // Warn about extraneous dependencies in TypeScript files
"no-param-reassign": "off", // Allow parameter reassignment
"consistent-return": "off", // Disable consistent return requirement
"no-empty-pattern": "off", // Allow empty destructuring patterns
"no-use-before-define": "off", // Disable "use before define" for all variables and functions
"no-shadow": "off", // Disable shadowed variable rule
"@typescript-eslint/no-shadow": "off", // Disable shadowed variable rule for TypeScript
"@typescript-eslint/no-use-before-define": "off", // Disable "use before define" for TypeScript
"react/jsx-no-constructed-context-values": "off", // Allow constructed context values in React
"import/extensions": "off", // Disable import extensions requirement (TypeScript handles this)
"react/function-component-definition": "off", // Allow different ways to define function components
"react/destructuring-assignment": "off", // Disable mandatory destructuring in React components
"react/require-default-props": "off", // Allow non-defined props to be undefined
"react/jsx-props-no-spreading": "off", // Allow prop spreading in JSX (e.g., in _app.tsx or react-hook-form)
"react/no-unstable-nested-components": "off", // Allow unstable nested components (needed by i18n library)
"@typescript-eslint/comma-dangle": "off", // Disable ESLint comma-dangle rule to avoid conflict with Prettier
"@typescript-eslint/consistent-type-imports": "error", // Enforce consistent usage of `import type`
"no-restricted-syntax": [
"error",
"ForInStatement", // Disallow `for-in` loops
"LabeledStatement", // Disallow labeled statements
"WithStatement" // Disallow `with` statements
], // Override Airbnb configuration to restrict specific syntax
"import/prefer-default-export": "off", // Allow named exports without preferring default exports
"simple-import-sort/imports": "error", // Enforce sorted imports
"simple-import-sort/exports": "error", // Enforce sorted exports
"import/order": "off", // Disable import order rule to avoid conflict with simple-import-sort
"@typescript-eslint/no-unused-vars": "off", // Disable unused variables rule for TypeScript
"unused-imports/no-unused-imports": "error", // Automatically remove unused imports
"no-unused-vars": "off", // Disable unused variables rule (covered by unused-imports plugin)
"@typescript-eslint/naming-convention": "off", // Disable naming convention rule (can be enabled if desired)
"unused-imports/no-unused-vars": [
"warn",
{
"vars": "all", // Warn for all unused variables
"varsIgnorePattern": "^_", // Ignore variables starting with an underscore
"args": "after-used", // Only warn about unused arguments if they appear after used ones
"argsIgnorePattern": "^_" // Ignore arguments starting with an underscore
}
]
}
}
]
}
Lastly, we should add a script in our package.json
file to automatically lint our Nextjs project and format our code globally.
To do this, go into your package.json
file and add the following script:
"scripts": {
"format": "next lint --fix && prettier '**/*.{json,yaml}' --write --ignore-path .gitignore",
// ...
},
This script will test your code against the rules specified in our eslint configuration.
The script will also apply prettier to any json and yaml files to make them look "prettier".
VSCode Configuration
If you are using vscode you can receive eslint warnings and errors for individual files while coding.
Also, you will be able to lint your file on save, which is my favorite feature and supercharges productivity.
To get started, create a .vscode
folder in the root of your project and add a settings.json
file inside it with the following settings:
{
"editor.formatOnSave": true,
"eslint.format.enable": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.validate": ["javascript", "typescript"],
"eslint.nodePath": "./node_modules/eslint"
}
And if you haven't already, type ctrl+shift+x
in your vscode editor and search for the "prettier" and "eslint" plugins and download them.
Conclusion
That's all there is to it!
Now if you run pnpm format
in your terminal, all of your codebase should be linted, and you will potentially see a lot of errors that you must fix.
But after fixing all these errors, your codebase will be clean, consistent, and make you code faster in the future.
If you enjoyed this article, please make sure to Subscribe, Clap, Comment and Connect with me today! 🌐
Want to ship code like a hacker? Visit Next Inject today!