Boost Your Next.js Productivity: A Comprehensive Guide to Setting Up Next.js with ESLint, Prettier, Husky, and Lint-Staged

J.A. ShezanJ.A. Shezan
9 min read

Tools

Before we move forward, let's take a quick refresher on what we will be exploring here.

TypeScript

Typescript is a programming language that serves as a syntactic extension of Javascript by introducing types and type safety capabilities.

Eslint

Eslint is a static code analysis tool that checks your code for errors and enforces coding standards.

Prettier

Prettier is an opinionated formatting tool that enforces consistent coding style. Eslint can check formats, but Prettier is more extensive and delegated.

Husky

Husky acts as a gatekeeper, preventing commits that don't pass certain checks. It allows you to define custom hooks that run before or after specific Git actions (like commit, push, etc.).

Lint-staged

Lint-Staged focuses on running linters (like ESLint and Prettier) only on the files that are staged for commit. This prevents unnecessary linting of unchanged files, improving performance.

Just a random unrelated wallpaper

Husky and Lint-Staged are powerful tools that work together to ensure your code adheres to quality standards before it's committed to your Git repository.

Together, Husky and Lint-Staged provide a robust mechanism to:

  • Enforce coding standards: Ensure your code adheres to consistent formatting and style guidelines.

  • Catch errors early: Identify potential issues before they make their way into your codebase.

  • Improve code quality: Maintain a high standard of code quality throughout your project's lifecycle.

Configuring the above tools to work together might seem a bit tricky and confusing at first, and it may occasionally disrupt an existing ESLint setup. However, once you get it set up, you can use it as a template and save time on future projects.

1. Creating a Next.js Project Using the CLI

Create and name the app as my-app with typescript and eslint pre-configured.

1.1 Creating a project without TypeScript

npx create-next-app@latest

On installation, you'll see the following prompts:

What is your project named? my-app
Would you like to use TypeScript? No / Yes
Would you like to use ESLint? No / Yes
Would you like to use Tailwind CSS? No / Yes
Would you like to use `src/` directory? No / Yes
Would you like to use App Router? (recommended) No / Yes
Would you like to customize the default import alias (@/*)? No / Yes
What import alias would you like configured? @/*

After the prompts, create-next-app will create a folder with your project name and install the required dependencies.

1.2 Creating a project with TypeScript

npx create-next-app@latest --typescript --eslint

This will create a project with TypeScript and ESLint, and will not prompt for these two.

What is your project named? my-app
Would you like to use Tailwind CSS? No / Yes
Would you like to use `src/` directory? No / Yes
Would you like to use App Router? (recommended) No / Yes
Would you like to customize the default import alias (@/*)? No / Yes
What import alias would you like configured? @/*

2. Adding ESLint After Next.js Project Initialization

If not selected during Next.js installation.

If you skipped ESLint configuration during the initial setup, you can easily add it later. Here's how to do it for both JavaScript and TypeScript projects:

2.1 Installing ESLint in a JavaScript project

  1. Install ESLint:

    Run the following command to install ESLint as a development dependency:

     npm i -D eslint eslint-config-next
    
  2. Initialize ESLint:

    After installation, you need to initialize ESLint:

     npx eslint --init
    

    You will be prompted with questions to configure ESLint:

    • How would you like to use ESLint? To check syntax, find problems, and enforce code style

    • What type of modules does your project use? JavaScript modules (import/export)

    • Which framework does your project use? React

    • Does your project use TypeScript? No

    • Where does your code run? Browser

    • What format do you want your config file to be in? JavaScript

This generates an .eslintrc.js configuration file.

  1. Add a Lint Script:

    Update your package.json to include a linting script:

     "scripts": {
       "lint": "eslint ."
     }
    

    You can now run linting with:

     npm run lint
    

2.2 Adding ESLint for TypeScript projects

If you're working with TypeScript, you'll need additional plugins for TypeScript linting.

  1. Install ESLint and TypeScript Plugins:

    Run the following command to install ESLint and the required TypeScript plugins:

     npm i -D eslint eslint-config-next @typescript-eslint/parser @typescript-eslint/eslint-plugin
    
  2. Initialize ESLint:

    Now initialize ESLint:

     npx eslint --init
    

    Answer the same set of prompts, but this time, make sure to answer Yes when asked if your project uses TypeScript:

    • How would you like to use ESLint? To check syntax, find problems, and enforce code style

    • What type of modules does your project use? JavaScript modules (import/export)

    • Which framework does your project use? React

    • Does your project use TypeScript? Yes

    • Where does your code run? Browser

    • What format do you want your config file to be in? JavaScript

  3. Update ESLint Configuration for TypeScript:

    After the initialization process, you'll need to update your .eslintrc.js file to include TypeScript settings. Here's an example:

     module.exports = {
       parser: '@typescript-eslint/parser',
       extends: [
         'eslint:recommended',
         'plugin:@typescript-eslint/recommended',
         'next/core-web-vitals',
       ],
       plugins: ['@typescript-eslint'],
       rules: {
         '@typescript-eslint/no-unused-vars': 'warn',
         'no-console': 'warn',
       },
     };
    
  4. Add a Lint Script:

    As with the JavaScript setup, make sure your package.json has a lint script:

     "scripts": {
       "lint": "eslint ."
     }
    

    Run linting with:

     npm run lint
    

This setup configures ESLint from scratch and ensures you have TypeScript-specific linting in place when needed.

After This Section .eslintrc.json will look like:

{
  "extends": ["next/core-web-vitals", "next/typescript"]
}

3. Setting Up Prettier

Prettier is a code formatter that helps maintain a consistent style across your project by automatically formatting your code according to defined rules.

  1. Install Prettier:

    Install Prettier as a development dependency:

     npm i -D prettier
    
  2. Create a .prettierrc File:

    Add a .prettierrc configuration file in the root of your project to define Prettier’s rules. Example:

     {
       "semi": true,
       "singleQuote": true,
       "trailingComma": "es5",
       "tabWidth": 2
     }
    
  3. Create a .prettierignore File:

    Specify the files and directories that Prettier should ignore by creating a .prettierignore file:

     node_modules
     .next
     build
    
  4. Add a Format Script:

    Update your package.json to include a script for formatting your code:

     "scripts": {
       "format": "prettier --write ."
     }
    
  5. Run Prettier:

    To format your code, run:

     npm run format
    

4. Integrating Prettier with ESLint in Next.js

To ensure that Prettier and ESLint work well together in a Next.js project, you can integrate Prettier as a plugin within ESLint. This way, ESLint will run Prettier checks automatically, and you can catch any format issues as ESLint errors.

4.1 Prettier with ESLint in a JavaScript Project

  1. Install Required Dependencies:

    In order to integrate Prettier with ESLint, you need to install additional packages:

     npm i -D eslint-plugin-prettier eslint-config-prettier
    
  2. Update ESLint Configuration:

    Open the .eslintrc.js file and extend the configuration to include Prettier:

     module.exports = {
       extends: [
         'eslint:recommended',
         'plugin:react/recommended',
         'next/core-web-vitals',
         'prettier' // Ensure this is at the end to override conflicting rules
       ],
       plugins: ['prettier'],
       rules: {
         'prettier/prettier': 'error', // Report Prettier formatting issues as ESLint errors
       },
     };
    

    This configuration will ensure that Prettier runs as part of the ESLint process and that any formatting issues are displayed as errors in ESLint.

  3. Add a Format and Lint Script:

    Update package.json to add both linting and formatting scripts:

     "scripts": {
       "lint": "eslint .",
       "format": "prettier --write ."
     }
    
  4. Run ESLint with Prettier:

    To lint your code and check for both ESLint and Prettier issues, run:

     npm run lint
    

4.2 Prettier with ESLint for TypeScript Projects

In a TypeScript project, you’ll follow similar steps, with some additional TypeScript-specific configurations.

  1. Install Required Dependencies:

    Install Prettier, along with ESLint plugins for both Prettier and TypeScript:

     npm i -D eslint-plugin-prettier eslint-config-prettier @typescript-eslint/parser @typescript-eslint/eslint-plugin
    
  2. Update ESLint Configuration for TypeScript:

    Extend your .eslintrc.js file to integrate Prettier, making sure that TypeScript-specific rules are included:

     module.exports = {
       parser: '@typescript-eslint/parser',
       extends: [
         'eslint:recommended',
         'plugin:@typescript-eslint/recommended',
         'next/core-web-vitals',
         'prettier', // Must be at the end
       ],
       plugins: ['@typescript-eslint', 'prettier'],
       rules: {
         'prettier/prettier': 'error',
       },
     };
    

    For ESLint version > 9.0

    eslint.config.mjs :

     import prettier from "eslint-plugin-prettier";
     import globals from "globals";
     import tsParser from "@typescript-eslint/parser";
     import path from "node:path";
     import { fileURLToPath } from "node:url";
     import js from "@eslint/js";
     import { FlatCompat } from "@eslint/eslintrc";
    
     const __filename = fileURLToPath(import.meta.url);
     const __dirname = path.dirname(__filename);
     const compat = new FlatCompat({
       baseDirectory: __dirname,
       recommendedConfig: js.configs.recommended,
       allConfig: js.configs.all,
     });
    
     const eslintConfig = [
       ...compat.extends(
         "next/core-web-vitals",
         "next/typescript",
         "eslint:recommended",
         "plugin:@next/next/recommended",
         "plugin:@typescript-eslint/recommended",
         "plugin:prettier/recommended",
         "plugin:prettier/tailwindcss",
       ),
       {
         plugins: {
           prettier,
         },
    
         languageOptions: {
           globals: {
             ...globals.browser,
           },
    
           parser: tsParser,
           ecmaVersion: 12,
           sourceType: "module",
    
           parserOptions: {
             ecmaFeatures: {
               jsx: true,
             },
           },
         },
    
         rules: {
           "@typescript-eslint/no-explicit-any": "off",
    
           "prettier/prettier": [
             "error",
             {
               endOfLine: "auto",
             },
           ],
    
           "react/react-in-jsx-scope": "off",
         },
       },
     ];
    
     export default eslintConfig;
    
  3. Add Lint and Format Scripts:

    Update package.json:

     "scripts": {
       "lint": "eslint . --ext .ts,.tsx,.js,.jsx",
       "format": "prettier --write ."
     }
    

    This ensures that both TypeScript (.ts, .tsx) and JavaScript (.js, .jsx) files are linted and formatted.

  4. Run ESLint with Prettier for TypeScript:

    Run the linting command:

     npm run lint
    

Integrating Prettier with ESLint helps avoid conflicts between the two tools and ensures that Prettier formatting is applied during the linting process for both JavaScript and TypeScript projects.

5. Prettier with Tailwind (If Chosen During Next.js CLI Setup)

To ensure your Tailwind CSS classes are sorted automatically, use the prettier-plugin-tailwindcss.

  1. Install the Plugin:

     npm i -D prettier-plugin-tailwindcss
    
  2. Update the Prettier Configuration:

    Add the prettier-plugin-tailwindcss to your. .prettierrc.json:

     {
       "plugins": ["prettier-plugin-tailwindcss"]
     }
    

​This plugin will automatically sort tailwind classes, ensuring a consistent order.

6. Setting Up Husky for Git Hooks

Husky lets you add Git hooks for tasks like linting.

Lint-staged ensures that only staged files are linted and formatted. In your project directory, run the following command to install husky.

npm install --save-dev husky
npx husky install

To automatically have Git hooks enabled after install, edit package.json

npm pkg set scripts.prepare="husky install"

After running this you should have this in your package.json

{
"scripts": {
    "prepare": "husky install"
  }
}

The init command simplifies setting up husky in a project. It creates a pre-commit script in .husky/ and updates the prepare script in package.json.

npx lint-staged -r -p false

7. Setting Up lint-staged

Lint-staged ensures that only staged files are linted and formatted.Run below to install it.

npm install lint-staged --save-dev

Lint-staged and Husky will work together to run Prettier and ESLint on staged files before each commit.

In your root directory, create a file .lintstagedrc.json

{
    ".js": ["eslint --fix", "prettier --write"],
    ".jsx": ["eslint --fix", "prettier --write"],
    ".ts": ["eslint --fix", "prettier --write"],
    ".tsx": ["eslint --fix", "prettier --write"],
    ".json": ["prettier --write"],
    ".md": ["prettier --write"]
}

try to verify it by running npx lint-staged.

Create a new file commit-msg file inside the .husky folder. and add the below content to it

npx --no-install commitlint --edit $1

Create a new file .commitlintrc.json and the below content to it

{
    "extends": [
        "@commitlint/config-conventional"
    ]
}

Here are some examples of valid commit messages that should pass the commitlint checks:

// Without Scope:
feat: add new feature for user authentication
// With Scope:
fix(api): correct API endpoint URL
// With Scope and Additional Details:
chore(config): update ESLint configuration

Ensure your commit message includes a type and a subject. For example:

git commit -m "chore: Updated the eslint configuration"
git commit -m "fix: correct spelling in README"

Conclusion

There you have it. You now have a Nextjs app with a working ESLint that works with Typescript and Prettier.

Hope this helps!

0
Subscribe to my newsletter

Read articles from J.A. Shezan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

J.A. Shezan
J.A. Shezan

Shezan loves technology who is currently studying Computer Science and Engineering. He codes frontend & backend of a website. He also does penetration testing on web apps.