Setting up a ESLint, Prettier, Husky and lint-staged Integration with TypeScript in Next.js 13 | 14

Vijay
YavarTechWorks
Published in
6 min readFeb 29, 2024

Next.js brings exciting updates and improvements, making it even more powerful and user-friendly. In this blog post, we’ll explore how to set up ESLint, Prettier, Husky and lint-staged in a Next.js project to ensure consistent code quality and maintainability.

Why Use ESLint, Prettier, Husky, and lint-staged?

ESLint: A widely used tool for identifying and fixing common programming errors and enforcing code style.
Prettier: A code formatter that helps maintain a consistent code style across the project.
Husky: A tool that allows you to run scripts (such as linters) before committing or pushing code.
lint-staged: Used in conjunction with Husky to run linters on pre-committed files only, improving performance.

Step 1: Create a Next.js Project

If you haven’t already, create a new Next.js project using the following command:

npx create-next-app@latest

On installation, you’ll see the following prompts:

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

After the prompts, create-next-app will create a folder with your project name

Step 2: Install Dependencies

Install the necessary dependencies for ESLint, Prettier, Husky, and lint-staged:

npm add --dev eslint prettier husky lint-staged eslint-config-prettier @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-prettier prettier-plugin-tailwindcss eslint-config-next

Step 3: Create Prettier Configurations

Create an Prettier configuration file (.prettierrc) and a Prettier ignore file (.prettierignore):

.prettierrc:

The .prettierrc file is a JSON or YAML configuration file that contains settings for Prettier. It allows you to define various options and preferences for code formatting.

{
"bracketSpacing": true,
"endOfLine": "lf",
"printWidth": 80,
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all",
"plugins": ["prettier-plugin-tailwindcss"]
}

bracketSpacing: Adds spacing inside object literals.
endOfLine: Defines the line ending style (lf stands for line feed, which is commonly used in Unix and Linux).
printWidth: Specifies the maximum line width for your code.
semi: Enforces or omits semicolons at the end of statements.
singleQuote: Uses single quotes instead of double quotes for strings.
tabWidth: Specifies the number of spaces per indentation level.
trailingComma: Adds trailing commas wherever possible.
plugins: Specifies additional plugins to be used. In this case, it includes the prettier-plugin-tailwindcss plugin.

.prettierignore

The .prettierignore file is used to specify files or directories that should be excluded from formatting by Prettier. This file follows the same pattern as .gitignore. You can list files, directories, or patterns that Prettier should ignore when formatting your code.

.next
.cache
package-lock.json
public
node_modules
next-env.d.ts
next.config.ts
yarn.lock

Step 4: Create ESLint Configurations

Create an ESLint configuration file (.eslintrc.js) and a ESLint ignore file (.eslintignore):

.eslintrc.js:
The .eslintrc.js file is the main ESLint configuration file for your project. It contains a JavaScript object that defines the ESLint settings and rules to be applied to your codebase.

module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2021,
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
},
env: {
browser: true,
es2021: true,
node: true,
},
root: true,
extends: [
'next',
'eslint:recommended',
'prettier',
'next/core-web-vitals',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:prettier/recommended',
'plugin:react-hooks/recommended',
],
plugins: ['prettier', '@typescript-eslint', 'react', 'react-hooks'],
rules: {
// JavaScript rules
'prefer-const': 'warn',
'no-var': 'warn',
'no-unused-vars': 'warn',
'object-shorthand': 'warn',
'quote-props': ['warn', 'as-needed'],
// TypeScript rules
'@typescript-eslint/array-type': [
'warn',
{
default: 'array',
},
],
'@typescript-eslint/consistent-type-assertions': [
'warn',
{
assertionStyle: 'as',
objectLiteralTypeAssertions: 'never',
},
],
// React rules
'react/jsx-fragments': ['warn', 'syntax'], // Shorthand syntax for React fragments
'react/jsx-filename-extension': [
'warn',
{
extensions: ['ts', 'tsx'],
},
],
'react-hooks/rules-of-hooks': 'error', // Checks rules of Hooks
'react-hooks/exhaustive-deps': 'warn', // Checks effect dependencies
'react/react-in-jsx-scope': 'off',
'react/prop-types': 'off',
'prettier/prettier': 'warn',
},
settings: {
react: {
version: 'detect',
},
},
};

parser and parserOptions: Specifies the parser and parser options for ESLint. I using @typescript-eslint/parser for TypeScript code and setting parser options like ECMAScript version, module type, and features.

env: Defines the environment for your code. It indicates which global variables are predefined. I targeting the browser, ECMAScript 2021, and Node.js environments.

root: Indicates that ESLint should stop looking for configuration files in parent directories. It defines the root of your ESLint configuration.

extends: Extends configurations from other files or plugins. I extending configurations for Next.js, ESLint recommended rules, Prettier, TypeScript, React, and React Hooks.

plugins: Lists the ESLint plugins you want to use. I have plugins for Prettier, TypeScript, React, and React Hooks.

rules: Specifies ESLint rules and their configurations. I have set various rules for JavaScript, TypeScript, and React, as well as Prettier and React Hooks.

settings: Configuration for various ESLint plugins. In this case, I configuring the React plugin to automatically detect the React version.

.eslintignore:
The .eslintignore file is used to exclude specific files and directories from ESLint linting. It follows the same pattern as .gitignore. You list files, directories, or patterns that you want ESLint to ignore when analyzing your code. This is useful for excluding build artifacts, third-party libraries, or any files you don’t want ESLint to process.

.next
.cache
package-lock.json
public
node_modules
next-env.d.ts
next.config.ts
yarn.lock

Step 5: Create Husky Configurations

Create an Husky configuration file (.huskyrc):

.huskyrc

The .huskyrc file is used to configure Git hooks using the Husky tool. Husky is a tool that allows you to easily set up and manage Git hooks in your project. Git hooks are scripts that run at specific points in the Git workflow, such as before a commit (pre-commit), before a push (pre-push), etc.

{
"hooks": {
"pre-commit": "lint-staged"
}
}

I have defined a single Git hook: pre-commit. This hook is set to run the lint-staged command before each commit. Here’s a breakdown:

pre-commit: This is the name of the Git hook. It corresponds to the hook that runs just before a commit is made.

lint-staged: This is the command that will be executed when the pre-commit hook is triggered. lint-staged is a tool that runs linters (code style checkers, etc.) on files that are staged for the commit.

So, whenever you try to make a commit, the lint-staged command will be executed, potentially checking and formatting the staged files according to the rules you have defined.

Make sure you have lint-staged and its configurations set up properly in your project, as it seems to be an integral part of your pre-commit workflow.

And to initialize the our pre-commit hooks run:

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 husky init

and

npx husky add .husky/pre-commit "npx lint-staged"

Step 6: Create Lint Stage Configurations

Create an Lint Stage configuration file (.lintstagedrc):

.lintstagedrc

The .lintstagedrc file is used to configure the behavior of lint-staged, a tool that runs linters on pre-committed files in a Git repository. lint-staged helps ensure that only files that pass certain linting checks are committed to the version control system.

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

*/**/*.{js,jsx,ts,tsx}: This pattern matches all files with extensions .js, .jsx, .ts, and .tsx in any directory. For these files, lint-staged will run the following commands:

prettier — write: Formats the code using Prettier and writes the changes back to the file.
eslint — fix: Automatically fixes linting errors using ESLint.
eslint: Runs ESLint to check for linting errors. It is run after fixing to catch any remaining issues.
*/**/*.{json,css,md}: This pattern matches all files with extensions .json, .css, and .md in any directory. For these files, lint-staged will run the following command:

prettier — write: Formats the code using Prettier and writes the changes back to the file.

Step 7: Add Scripts to package.json

Add scripts to your package.json:

  "scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start -p 4000",
"lint": "next lint",
"lint:fix": "next lint --fix",
"lint:strict": "next lint '*/**/*.{js,jsx,ts,tsx}'",
"prettier": "prettier --write */**/*.{js,jsx,json,ts,tsx,scss,css,md}",
"prepare": "husky install"
},

Step 8: Test Your Setup

Now, test your setup by running the lint and prettier scripts:

npm run lint
npm run lint:fix
npm run lint:strict
npm run prettier

Conclusion:

By setting up ESLint, Prettier, Husky, and lint-staged in your Next.js project, you ensure a consistent code style and catch potential issues early in the development process. This leads to cleaner code and a more efficient and collaborative development workflow. Happy coding with Next.js!

--

--