Automatically lint & format your code on commit when using Next.js
Tags: nextjs, react, git, javascript
Published: 2021-07-24 16:05:35

_In this post, we will be setting up [Next.js](https://nextjs.org/) with [Husky](https://typicode.github.io/husky/#/) and [lint-staged](https://github.com/okonet/lint-staged) to run [ESLint](https://eslint.org/) and [Prettier](https://prettier.io/) whenever we commit a file._

If you want to take a look at the final product first, or if you don't care about the step-by-step, here's [the accompanying repo](https://github.com/jonasmerlin/next-lint-on-commit).

You probably already know, or can imagine, the advantages of automatically linting and formatting each and every piece of code commited to your repo. So I won't convince you of its merits here, but get straight into the action.

## Set up a new Next.js Project

Start by setting up a new Next.js project if you don't have one yet:

```bash
npx create-next-app --typescript
# or
yarn create next-app --typescript
```

Here, we are using the Typescript template. But you can simply leave the `--typescript` off if you like to suffer. Your choice, really.

Choose whatever name you want. I'll presume you chose "website" though.

_If you want to read more about the process of setting up Next.js, take a look at their [getting started guide](https://nextjs.org/docs/getting-started)_.


## Install Prettier as a devDependency

ESLint will look at your code and try to prevent potential bugs by looking at its semantics. Prettier will look at the formatting and change it according to its rules. Since Next.js comes with ESLint pre-installed and pre-configured, that's already taken care of. That leaves Prettier.

Change into your newly created project folder:

```bash
cd website
```

Then, install Prettier as a devDependency:

```bash
npm install --save-dev --save-exact prettier
# or
yarn add --dev --exact prettier
```

Create an empty Prettier config:

```bash
echo {}> .prettierrc.json
```

This will let tools like your editor know you are using Prettier.

### Optional: Create a .prettierignore file

If you plan to use Prettier outside of the Git hook we are setting up below, you should probably create a `.prettierignore` file. This allows you to list folders and files you don't want to format.

```bash
touch .prettierignore
```

The Prettier documentation says it's a good idea to base this on your "gitignore and .eslintignore (if you have one)." So ... do that.

_If you want to read more about the process of setting up Prettier, take a look at their [installation guide](https://prettier.io/docs/en/install.html)_.

## Edit your .eslintrc

Some of the ESLint rules Next.js comes pre-configured with are about formatting. But we want Prettier to handle everything related to the formatting of our code. This is why we'll install [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) and add it to our `.eslintrc`, where it will disable all existing rules that might interfere with Prettier.

Install eslint-config-prettier by running the following:

```bash
npm install --save-dev eslint-config-prettier
# or
yarn add --dev eslint-config-prettier
```

The `.eslintrc` Next.js created should look like the following:

```json
// In file .eslintrc
{
  "extends": ["next", "next/core-web-vitals"]
}
```

Change this to the following:

```json
// In file .eslintrc
{
  "extends": ["next", "next/core-web-vitals", "prettier"]
}
```

_If you want to read more about the process of combining ESLint and Prettier in a Next.js project, take a look at [the Next.js "Usage with Prettier" guide](https://nextjs.org/docs/basic-features/eslint#usage-with-prettier), as well as [Prettier's "Integrating with Linters" guide](https://prettier.io/docs/en/integrating-with-linters.html)_.

## Install lint-staged

At this point, you would be able to run ESLint and Prettier manually. But ain't nobody got time for that. Also, "__Manually__ Lint & Format your Code on Commit When Using Next.js" is not the title of this article and I don't want to disappoint you. So let's introduce lint-staged into the mix.

The good thing is that they make it very easy to set up:

```bash
npx mrm@2 lint-staged
```

This will install Husky, a tool that makes is easy to manage Git hooks, and detect which linting and formatting tools are already installed. It will then set everything up more or less correctly. We'll come to the "less" part next.

_If you want to read more about the process of setting up lint-staged, take a look at [their installation and setup guide](https://github.com/okonet/lint-staged#installation-and-setup), as well as [Prettier's pre-commit hook guide](https://prettier.io/docs/en/precommit.html)_.

## Edit the Git Hook

After running the above, you should have the following entry in your `package.json`:

```json
// In file package.json

// ...
"lint-staged": {
  "*.js": "eslint --cache --fix",
  "*.{js,css,md}": "prettier --write"
}
```

Change this to the following:

```json
// In file package.json

// ...
"lint-staged": {
  "*.{js,jsx,ts,tsx,css,md}": "prettier --write"
}
```

This will run Prettier on all staged files of the listed types when you run `git commit`.

Now, you would be forgiven to assume that to also run ESLint, we should put it in there as well. But since Next.js comes with its own pre-configured wrapper around ESLint, wich doesn't take the files it operates on as arguments, we will do something slightly different. We will edit the Git hook that Husky created, during the installation of lint-staged, directly. Right now, it should look like this:

```bash
# In file .husky/pre-commit

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx lint-staged
```

Change this to the following:


```bash
# In file .husky/pre-commit

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn lint:write && npx lint-staged
```

And then add the following script to your `package.json`:

```json
// In file package.json

// ...
"scripts": {
  // ...
  "lint:write": "next lint --cache --fix",
},
```

This will call the Next.js version of ESLint and tell it to automatically `--fix` any issues that it finds that can be fixed automatically. Also, the `--cache` tells it to only do so on changed files.

_If you want to read more about the undocumented command line options Next.js' lint command accepts, take a look at my [post on the topic](https://dev.to/jonasmerlin/eslint-command-line-options-supported-by-next-lint-incl-fix-18c8)_.

## We're Done!

Now, when you run `git commit`, both ESLint and Prettier should check that you don't commit any crap. This should also work when using VSCode's own Git UI. Other Git UIs might have issues though. Sublime Merge for example can't find my node.js installation, most likely because it's installed and managed via nvm. There are almost certainly solutions to this, but since I haven't looked them up yet they fall outside the scope of this tutorial.

Don't forget that you can use or take a look at [the accompanying repo](https://github.com/jonasmerlin/next-lint-on-commit).

Hope you found this helpful. If you find any erros or run into issues, feel free to tell me in the comments.

>💡 This post was published 2021/07/14 and last updated 2021/07/14. Since node libraries change and break all the time, there's a non-trivial chance that all of this is obsolete and none of it works when you read this in your flying taxi, gulpin' on insect protein shakes sometime in the distant future or, let's be honest here, next week. If so, tell me in the comments and I'll see if an update would still be relevant.