DEV Community

Cover image for Just use this Next.js Eslint Configuration
Jordan Haines
Jordan Haines

Posted on

Just use this Next.js Eslint Configuration

Here, Take this Configuration

I get it. If you're just here to find a good, working ESLint configuration for a NextJS project, then look no further. Copy what's below. Although, it's probably out of date, so you can find a version that's been updated since I published this post in my open source project Historio ➡️ in Github here ⬅️.

eslint.config.mjs

Run this command to install necessary npm packages:

npm i --save eslint typescript-eslint eslint-config-next eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-tailwindcss eslint-plugin-unicorn
Enter fullscreen mode Exit fullscreen mode

Why Lint

When starting a new project, the very first thing I do is write some really sloppy, hacky, and messy code that (mostly) just works. I'm trying to validate an idea; to get a product off the ground.

This lasts all of about 2 pull requests before it gets out of hand, and I need some rules. You can see the exact moment in Historio where I realized inconsistent code was holding me back in this pull request where linting was first applied.

Having conventions on shared projects helps keep everyone aligned and working in the same direction. Conventions allow us to focus code reviews and discussion on the logic problems that matter instead of the semicolon placement or tab size that - frankly - only matter because they’re a distraction. Written conventions for a team, starting with a style guide but encompassing any rules that keep engineers focused on engineering, are thus essential.

The benefits to a team may be obvious, but even individual projects deserve conventions. Perhaps even stricter ones. Indeed, when I’m working on a project alone, I tend to codify a larger set of conventions than I would with a team simply because I get to do everything exactly my way. It's unclear if this is software engineering bliss or OCD. Every convention eliminates decisions I would otherwise have to make in the future (often many times over). Further, without a colleague to review every line of code I write, conventions help keep me consistent and tidy even when I really want to move fast.

How I Arrived at this Configuration

Other coders have thought longer and harder about conventions than I ever want to. When spinning up a new linting configuration or style guide, I look to what already exists. For my stack, this includes the following ESLint Plugins. For each, I start with their recommended config:

Additionally, here are a few plugins I evaluated but decided not to use:

  • AirBbB. I usually start here, but Vercel's config covered most of what I care about for both React and Node code styling.

  • XO. This feels like the Black of Typescript linting. XO has styles for everything and is very opinionated. This can be nice, because it takes a lot of code style decisions off of your plate. But beware it can be cumbersome to implement in the middle of a project because it will require extensive reformatting. In lieu of XO, I found Unicorn opinionated enough and more immediately useful.

Technical Note on ESLint Config

There are too many ways to configure ESLint. I started with the .eslintrcs.json config that came from create-next-app. However, this configuration is now deprecated in favor of eslint.config.mjs.

Because I couldn't easily extend this deprecated configuration, I (swore and then) scrapped it and initialized a new eslint config with npm init @eslint/config@latest. I then added the configuration for next wrapped with eslint's flat compat utility. Here's the snippet in eslint.config.mjs:

import { FlatCompat } from "@eslint/eslintrc"
export default const config = [
// other ESLint plugins and rulesets
...compat.config({
    extends: ["next"],
    settings: {
      next: {
        rootDir: ".",
      },
    },
  }),
]
Enter fullscreen mode Exit fullscreen mode

Most other plugins offer a configuration that can be plugged into eslint.config.mjs directly. But if you see an error starting with:

Support for loading ES Module in require() is an experimental feature and might change at any time
then you probably need to wrap a plugin with that flat config migration utility

Sharpen Skills by Exploring Linting Config

Ultimately, there is no single "right" style guide or linting configuration. You should choose what works best for your project. When creating or revisiting my configurations, I often uncover new tricks or coding conventions that make me a better software engineer. when putting together this configuration, I learned:

  • It's important to deal with the ambiguity of null and undefined in JS/TS, but how you do it is project-dependent. By default, unicorn encourages use of undefined over null always, but there are very legitimate reasons to use null, like if you have a lot of code that leverages an ORM with null values. This long thread has many great points and no single right answer.

  • Avoid passing a function reference directly to iterators (i.e. {elements.map(callback)}) details

Your style guide also shouldn't be static. It should evolve as your project grows. Not only do the needs of your project change, but conventions, libraries, and coding languages evolve around your work, too. It's okay (good, even) to make considered and reasoned changes to your conventions, even if you're backtracking on something you once felt was really important.

Top comments (1)

Collapse
 
jordanahaines profile image
Jordan Haines

What do you include in your Next.JS linting that I missed?