Configure ESLint, Prettier, Husky, lint-staged Properly for Next.js

J.A. ShezanJ.A. Shezan
5 min read

If you choosed TypeScript and ESLint during Next.js CLI, then this article is for you to setup Prettier, Husky, lint-staged properly to proceed ahead and great project structure. If you work with other developer or want to maintain the project in future, then this is a must-do for Next.js project

Packages Install

npm install -D eslint eslint-config-next eslint-config-prettier eslint-plugin-prettier prettier prettier-plugin-tailwindcss eslint-plugin-tailwindcss @typescript-eslint/eslint-plugin @typescript-eslint/parser husky lint-staged
  • eslint: The pluggable linting utility for JavaScript and JSX. ESLint is an open source project that helps you find and fix problems with your JavaScript code.

  • eslint-config-next: This package provides an ESLint configuration optimized for Next.js projects, ensuring adherence to Next.js best practices and conventions.

  • eslint-config-prettier: Disables ESLint rules that conflict with Prettier formatting, allowing Prettier to handle all code style concerns without interference.

  • eslint-plugin-prettier: Integrates Prettier into ESLint as a rule, enabling code to be automatically formatted by Prettier whenever ESLint runs.

  • prettier: A code formatter that enforces a consistent style by parsing and reformatting code according to predefined rules, ensuring readability across different projects.

  • prettier-plugin-tailwindcss: A Prettier plugin that automatically organizes Tailwind CSS class names in a consistent order according to Tailwind's recommendation.

  • eslint-plugin-tailwindcss: A ESLint plugin that automatically organizes Tailwind CSS class names in a consistent order according to Tailwind's recommendation and many more.

  • @typescript-eslint/eslint-plugin: Provides a set of ESLint rules specific to TypeScript, helping to catch and enforce best practices in TypeScript codebases.

  • @typescript-eslint/parser: An ESLint parser that allows ESLint to parse TypeScript code, enabling linting for TypeScript files.

  • husky: A tool that enables Git hooks, allowing commands like linting, testing, or formatting to run automatically at key stages of Git workflows, such as before committing.

  • lint-staged: A tool that runs linters or formatters on only the staged files in Git, ensuring that only the modified files are processed before a commit.

ESLint Config File

ESLint version > 9.0 support eslint.config.js, So eslint.config.mjs:

import prettier from "eslint-plugin-prettier";
import tailwindcss from "eslint-plugin-tailwindcss";
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:tailwindcss/recommended",
  ),
  {
    plugins: {
      prettier,
      tailwindcss,
    },
    languageOptions: {
      globals: {
        ...globals.browser,
        ...globals.node,
      },
      parser: tsParser,
      ecmaVersion: 12,
      sourceType: "module",
      parserOptions: {
        ecmaFeatures: {
          jsx: true,
        },
      },
    },

    rules: {
      "@typescript-eslint/no-explicit-any": "off",
      "react/react-in-jsx-scope": "off",
      "prettier/prettier": [
        "error",
        {
          endOfLine: "auto",
        },
      ],
    },
  },
];

export default eslintConfig;

Previous: eslintrc.json:

{
  "env": {
    "browser": true,
    "es2021": true
  },
  "extends": [
    "next/core-web-vitals",
    "next/typescript",
    "eslint:recommended",
    "plugin:@next/next/recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:prettier/recommended",
    "plugin:tailwindcss/recommended"
  ],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    },
    "ecmaVersion": 12,
    "sourceType": "module"
  },
  "plugins": [
    "prettier"
  ],
  "rules": {
    "@typescript-eslint/no-explicit-any": "off",
    "prettier/prettier": [
      "error",
      {
        "endOfLine": "auto"
      }
    ],
    "react/react-in-jsx-scope": "off"
  }
}

Prettier Config File

Newer: prettier.config.mjs:

// prettier.config.js, .prettierrc.js, prettier.config.mjs, or .prettierrc.mjs

/**
 * @see https://prettier.io/docs/en/configuration.html
 * @type {import("prettier").Config}
 */
const config = {
  trailingComma: "es5",
  tabWidth: 2,
  semi: true,
  singleQuote: false,
  bracketSpacing: true,
  arrowParens: "always",
  jsxSingleQuote: false,
  bracketSameLine: false,
  endOfLine: "lf",
  plugins: ["prettier-plugin-tailwindcss"],
  printWidth: 80,
  experimentalTernaries: false,
  tailwindConfig: "tailwind.config.ts",
  tailwindEntryPoint: "tailwind.config.ts",
  quoteProps: "as-needed",
  proseWrap: "always",
  htmlWhitespaceSensitivity: "css",
  embeddedLanguageFormatting: "auto",
  useTabs: false,
  requirePragma: false,  
  insertPragma: false,
  vueIndentScriptAndStyle: false,
  singleAttributePerLine: true,
};

export default config;

prettierrc.json:

{
  "printWidth": 80,
  "useTabs": false,
  "tabWidth": 2,
  "trailingComma": "es5",
  "semi": true,
  "singleQuote": false,
  "bracketSpacing": true,
  "arrowParens": "always",
  "jsxSingleQuote": false,
  "bracketSameLine": false,
  "endOfLine": "lf",
  "plugins": ["prettier-plugin-tailwindcss"]
}

Husky Configurations

Husky has been installed before during installations.

npx husky init

It creates a .husky/ folder where the Git hooks will reside and the .husky folder contains a file named “pre-commit“.

This will also add a new script in your package.json file:

  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "prepare": "husky",
  },

If not added, then please manually add this:

"prepare": "husky",

Add Pre-Commit Hooks:

Add necessary commands to this .husky/pre-commit file.

npx lint-staged

This will configure Husky.

Lint-staged Configurations

Next, configure lint-staged in your package.json same block as scripts to specify that ESLint and Prettier should run only on staged files. Add the following configuration:

"lint-staged": {
  "*.{js,jsx,ts,tsx}": [
    "eslint --fix './src/**/*.{js,jsx,ts,tsx}'",
    "prettier --write './src/**/*.{js,jsx,ts,tsx,css}'"
  ]
}

This configuration ensures that ESLint will fix any linting issues, and Prettier will format files before they are committed.

Update package.json Scripts

Add these to your scripts list of package.json:

"format": "prettier --check './src/**/*.{js,jsx,ts,tsx,css}'",
"format:fix": "prettier --write './src/**/*.{js,jsx,ts,tsx,css}'",
"lint:fix": "eslint --fix './src/**/*.{js,jsx,ts,tsx}'"

Now the script section of package.json will look like:

  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "prepare": "husky",
    "format": "prettier --check './src/**/*.{js,jsx,ts,tsx,css}'",
    "format:fix": "prettier --write './src/**/*.{js,jsx,ts,tsx,css}'",
    "lint:fix": "eslint --fix './src/**/*.{js,jsx,ts,tsx}'"
  },

Conclusion

This article offers a detailed setup guide for integrating Prettier, Husky, and lint-staged into a Next.js project using TypeScript and ESLint. It provides step-by-step instructions on installing the required packages, configuring ESLint and Prettier, setting up Husky for Git hooks, and configuring lint-staged to maintain code quality before committing changes. Furthermore, it updates project scripts for formatting and linting, ensuring a consistent and maintainable codebase when collaborating with other developers.

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.