0% found this document useful (0 votes)
34 views24 pages

How To Set Up ESLint, Prettier, StyleLint, and Lint-Staged in Next - Js

Uploaded by

holircon1218
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
34 views24 pages

How To Set Up ESLint, Prettier, StyleLint, and Lint-Staged in Next - Js

Uploaded by

holircon1218
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 24

12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.

js

How to Set Up ESLint, Prettier, StyleLint, and lint-staged


in Next.js
freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs

Naveed Ausaf September 16, 2024

Naveed Ausaf

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 1/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

A linter is a tool that scans code for potential issues. This is invaluable with a programming
language like JavaScript which is so loosely typed.

Even for TypeScript, which is a strongly typed language whose compiler does a great job of
detecting errors at compile time, linters such as ESLint have plugins that catch problems not
caught by the compiler.

When you generate a new app using the Next.js CLI (npx create-next-app), ESLint is
configured by default. But there are several problems with the linting setup generated by
create-next-app:

If you choose SCSS for styling, you should use Stylelint in the build process to lint CSS
or SCSS stylesheets. But it’s not set up automatically.

If instead you opt for Tailwind for styling, you should set up the Tailwind plugin for
ESLint. But again, this isn’t done in the generated ESLint configuration.

If you choose TypeScript, then in Next.js v14 and below, TypeScript-specific ESLint
rules are not configured, contrary to what the documentation states. While a Next.js
v15 app has these set up, I would still tweak the setup further with the more powerful
linting rules provided by the typescript-eslint project.

And finally, Prettier is not set up. Prettier is a code formatting tool. It can prevent
inconsistently formatted code from getting into the code repository, which would make
comparisons between different versions of the same file difficult. Also, nicely formatted
code is easier to work with. So this is a pretty big omission.

In this tutorial, I'll show you how I set up linting and formatting in my Next.js projects in a way
that addresses the issues above. I’ll also teach you how to install and configure some related
VS Code extensions for coding assistance.

To follow along, you can either use a Next.js project you already have, or generate a new
app by running npx create-next-app on the terminal.

If you’re scaffolding a new app, your choices are up to you (defaults are fine) but make sure
to choose YES in response to the question about whether you’d like to use ESLint:

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 2/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

If you are following along with an existing app rather than a new one, upgrade it by running
the following command in app root:

npm i next@latest react@latest react-dom@latest eslint-config-next@latest


npm i --save-dev eslint

This will avoid versioning conflicts down the line.

If you cannot upgrade to the latest version, you’ll need to specify versions for packages that
will be installed in this tutorial to get around any version conflicts. Be warned that this can be
frustrating.

Now you’re ready to open up the app in your code editor and proceed as follows.

Prerequisites
I assume that you know how to:

write a basic Next.js app with two or more pages.

install additional NPM packages into your app

Table of Contents
Introduction

Prerequisites

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 3/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

Table of Contents

Set Up Prettier

A note on line endings in Prettier


Set Up ESLint

Basics of ESLint configuration

ESLint Setup for TypeScript

ESLint Setup for Tailwind

ESLint Setup for Prettier

Set Up Stylelint

Set Up package.json Scripts

Set Up lint-staged

Set UP VS Code Extensions

Final Checks and Troubleshooting

Conclusion

Set Up Prettier
Prettier is an opinionated code formatter that can format pretty much any file (.html, .json,
.js, .ts, .css, .scss and so on).

Set it up in yuor app as follows:

1. Install Prettier:

npm install --save-dev prettier

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 4/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

2. If you chose Tailwind for styling when generating the app, then install prettier-
plugin-tailwindcss:

npm install --save-dev prettier-plugin-tailwindcss

This package is a Prettier plugin and provides rules for reordering of Tailwind classes
used in a class or className attribute according to a canonical ordering. It helps keep
the ordering of Tailwind classes used in the markup consistent.

%[https://youtu.be/tQkBJXwzY8A?autoplay=1]

3. Create .prettierrc.json in youyr project root. If you’re using SCSS for styling, paste
the following snippet into this file:

{
"singleQuote": true,
"jsxSingleQuote": true
}

If you’re using Tailwind instead, paste the following into .prettierrc.json:

{
"plugins": ["prettier-plugin-tailwindcss"],
"singleQuote": true,
"jsxSingleQuote": true
}

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 5/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

4. Create .prettierignore file in the app root, with the following content:

node_modules
.next
.husky
coverage
.prettierignore
.stylelintignore
.eslintignore
stories
storybook-static
*.log
playwright-report
.nyc_output
test-results
junit.xml
docs

This file ensure that files which are not app code (that is, those which are not .js, .ts,
.css files and so on.) do not get formatted. Otherwise Prettier will end up spending too
much time processing files whose formatting you don't really care about.

'prettierignore (the file we just created), .eslintignore, and .stylelintignore


have been ignored because these are plain text files with no structure so Prettier would
complain that it cannot format them.

5. Finally, I recommend that you follow the steps in this post to set LF as the EOL
character, both in the repo and in your VS Code settings. Reasoning for this is given in
the following subsection.

A note on line endings in Prettier

Prettier defaults to LF (Line Feed character) for line endings. This means that when it
formats files, it will change all occurrences of the CRLF character sequence, if any, to LF.

LF is also the default in text editors and other tools in Unix-based systems (Linux, MacOS
etc.). But on Windows, the default for line endings is CRLF (Carriage Return character,
followed immediately by Line Feed character).

Windows tooling such as text and code editors can easily handle LF as line ending. But
CRLF can be problematic for tools on Unix-based systems such as Linux and various
flavours of Unix. Therefore it makes sense to only use LF as line endings in code as this
would work on both Windows and Unix-based systems.

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 6/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

Configuring LF as the EOF character in Git repo and in code editors will bring your tooling in
line with Prettier's default. It will also ensure that all files in the Git repo consistently have LF
line endings. Thus if a contributor to your repo is on Windows which uses CRLF as EOL
character, the code they add or modify in the repo would still use LF: the code editor would
default new code files to LF; git commit` would convert any CRLFs to LF when committing.

Finally, setting LF as the line endings for the whole repo would avoid strange things that
happen when on Windows, Prettier retains its default of LF but Git and your code editor
continue to use their default of CRLF for line endings:

When VS Code Prettier extension formats a file (for example, when the extension is set
up to "autoformat on save"), it does not change CRLF line endings. But formatting the
same file by running Prettier on the command line does change line endings to LF.
This discrepancy can be annoying.

Git may show warnings like this when when you run git add .:

Set Up ESLint

Basics of ESLint configuration


ESLint comes with a number of linting rules out of the box. But you can also supplement
these with ESLint plugins.

An ESLint plugin defines some linting rules. For example, if you look in the GitHub repo for
Next's ESLint plugin, eslint-plugin-next, each file in the src/rules folder defines a linting rule
as a TypeScript function. The index.js of the package then exports these rule functions in
the rules object in its default export:

module.exports = {
rules: {
'google-font-display': require('./rules/google-font-display'),
'google-font-preconnect': require('./rules/google-font-preconnect'),
'inline-script-id': require('./rules/inline-script-id'),
...

The basic way to use these rules in your app is to install the plugin package, then reference
it in the ESLint configuration file in the app's root folder.

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 7/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

For example, we can use rules from the eslint-plugin-next mentioned above by running
npm install --save-dev eslint-plugin-next, then placing the following content in the
ESLint config file .eslintrc.json in the app root:

{
plugins: ["next"],
"rules": {
"google-font-display": "warning",
"google-font-preconnect": "warning",
"inline-script-id": "error",
}
}

If you now run npx eslint . in your app's root folder, ESLint will lint every JavaScript file in
the app against each of the three rules configured above.

There are three severities you can assign to a rule when configuring it for use: off, warning
and error. As the snippet above shows, you enable a rule by assigning to it a severity of
warning or error in the app's .eslintrc.json.

When referencing a plugin in your app's ESLint configuration file, the prefix eslint-plugin-
in the plugin's package name is omitted. This is why the package that contains linting rules
for Next.js, eslint-plugin-next, is referenced only as "next" in the snippet above.

Since it is quite cumbersome to configure a severity level - off, warning or error - for every
single rule from every plugin that you want to use, the norm is to reference an ESLint
configuration object, or ESLint config for short, that is exported by an NPM package. This
is a JavaScript object that declares plugins and configures rules from these with severity
levels just as we did above.

For example, the default export from eslint-plugin-next also contains several ESLint
configs. Here is a another snippet from index.js of the plugin, this time showing exported
ESLint configs in addition to the rules object for exporting rule functions:

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 8/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

module.exports = {
rules: {
'google-font-display': require('./rules/google-font-display'),
'google-font-preconnect': require('./rules/google-font-preconnect'),
'inline-script-id': require('./rules/inline-script-id'),
...
},
configs: {
recommended: {
plugins: ['@next/next'],
rules: {
// warnings
'@next/next/google-font-display': 'warn',
'@next/next/google-font-preconnect': 'warn',
...

// errors
'@next/next/inline-script-id': 'error',
'@next/next/no-assign-module-variable': 'error'
...

}
},
'core-web-vitals': {
plugins: ['@next/next'],
extends: ['plugin:@next/next/recommended'],
rules: {
'@next/next/no-html-link-for-pages': 'error',
'@next/next/no-sync-scripts': 'error',
},
},
}

As you can see, in addition to the rules (there are many more than those shown above), the
plugin also exports two configs - recommended and core-web-vitals - that enable different
selections of the rules defined in the plugin by assigning severity levels of error or warning
to them.

The config that is normally used in Next.js projects is core-web-vitals. We can use this
config object in our app’s ESLint configuration file (.eslintrc.json in app root) as follows:

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

Thus is much simpler than declaring the plugin in plugins object and then assigning a
severity level of error or warning to each rule from the plugin that we want to use.

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 9/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

Notice the difference between the configuration file - this is .eslintrc.json - and config -
this is an object that configures some rules from a plugin for use in a client project by
assigning severities to selected rules.

Contents of the configuration file are themselves a config. But in configuration files, we do
not typically import a plugin and configure all rules from it that we want to use. Instead we
almost always import a well-known/trusted config object that is exported by an NPM
package. Such a config object - one that is exported by an NPM package for use in ESLint
configuration files (in other packages/apps) - is also known as a shareable config.

Typically, plugins - these define ESLint rules as JavaScript/TypeScript functions - also bundle
their rules into one or more shareable configs. The recommended config from plugin eslint-
plugin-next that we used above is just one such config.

Shareable configs do not only come from plugin packages, although it is customary for
plugins to also export one or more shareable configs composed of their own rules. Other
packages, whose names begin with eslint-config- (as opposed to eslint-plugin-) can
provide one or more named configs.

Next.js provides one such package named eslint-config-next. This re-exports configs
recommended and core-web-vitals from the plugin. It also re-exports (in v15 and above of
the package) a config of TypeScript linting rules from plugin typescript-eslint/eslint-
plugin. So instead of using recommended config from the plugin like we have done above:

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

we could have installed the package eslint-config-next and used that in


.eslintrc.json:

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

Since the package's name is not prefixed with plugin:, ESLint considers it to be a config
package, reconstructing the name as eslint-config-next rather than as eslint-plugin-
next. Notice how with config packages also, we delete the canonical prefix eslint-config-
when referencing it in the ESLint configuration file.

It is possible to reference multiple shareable configs in extends. In this case, all the rules
from all configs are used - except where there are multiple configs that each provide a rule
with the same name. In this case the last config, proceeding left to right, wins. This is to say
where there is a naming conflict, ESLint will use the rule from the last config on the list.

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 10/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

It is possible to use ESLint configuration file formats other than JSON. You can provide the
same information as in an .eslintrc.json file in a JavaScript (.eslintrc.js or
.eslintrc.cjs) or yaml (.eslintrc.yml or .eslintrc.yaml) file instead.

Also, ESLint has a new configuration file format often called flat config (which I haven't used
here) where the config files are either JavaScript or TypeScript files.

Armed with an understanding of how to configure ESLint for use, you are ready to set up
ESLint in your Next.js project. The sections below shows you how to do this.

ESLint Setup for TypeScript

If your app uses TypeScript, modify the ESLint configuration file (.esilntrc.json) as follows:

1. On the terminal, in app's root folder, run the following command:

npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-


plugin typescript

@typescript-eslint/eslint-plugin provides a number of linting rules for TypeScript


files, as well as shareable configs, that augment the checking that the TypeScript
compiler does.

@typescript-eslint/parser is a parser that allows ESLint to parse TypeScript files


(by default it can only parser JavaScript files).

I am adding TypeScript compiler as a package - typescript - because typescript-eslint


Getting Started instructions do the same.

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 11/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

2. In app root folder, rename .eslintrc.json to .eslintrc.js. Then Replace contents


of .eslintrc.js in app root with the following:

/* eslint-env node */
module.exports = {
root: true,
extends: [
'next/core-web-vitals',
],
plugins: ['@typescript-eslint', 'tailwindcss'],
parser: '@typescript-eslint/parser',
overrides: [
{
files: ['*.ts', '*.tsx'],
parserOptions: {
project: ['./tsconfig.json'],
projectService: true,
tsconfigRootDir: __dirname,
},
extends: [
'next/core-web-vitals',
'plugin:@typescript-eslint/recommended',
//'plugin:@typescript-eslint/recommended-type-checked',
// 'plugin:@typescript-eslint/strict-type-checked',
// 'plugin:@typescript-eslint/stylistic-type-checked',
]
},
],
};

This is what the various lines of this file do:

/* eslint-env node */ stops ESLint from complaining that this is a CommonJS


module. We have had to put this in because ESLint, as we have configured it here,
does not allow CommonJS modules (which .eslintrc.js is, see module.exports =
... at the top) and expects modules in the project to be ES6.

root: true says this is the topmost ESLint configuration file even though there may be
nested ESLint configs in subfolders.

extends: specifies various ESLint configs, each of which enables a collection of linting rules.

'next/core-web-vitals' is a config provided by eslint-config-next that bundles Next.js-


specific rules (both for JavaScript and TypeScript, from an inspection of its code on GitHub).

The recommended-type-checked config (used in a nested extends within overrides object -


this is explained shortly) is provided by @typescript-eslint/eslint-plugin. This plugin is
part of the typescript-eslint project that publishes packages for linting rules and parsers to

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 12/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

support linting of TypeScript files by ESLint.

The configs used is described here. It is a superset of the non-type checked versions of the
config, recommended. It adds linting rules which use TypeScript's type checking API for
additional type information. These rules are more powerful than those contained in the base,
non-type-checked recommended config that only rely on the ESLint parser for TypeScript -
package @typescript-eslint/parser.

You might prefer to use the strict-type-checked and stylistic-type-checked configs,


also provided by @typescript-eslint/eslint-plugin. These are stricter than what I have
used.

The least strict choice for TypeScript linting would probably be the recommended config. This
is what is re-exported by eslint-plugin-next as config named typescript and is
referenced in Next.js instructions for setting up ESLint with TypeScript as next/typescript
(at least as of the time of this writing, September 2024). I prefer the config I have used
instead.

parser: '@typescript-eslint/parser' specifies the ESLint TypeScript parser to be used


instead of the default Espree parser which cannot parser TypeScript files.

parserOptions: tells the parser where to find the tsconfig.json file. This information
allows the rules in the type-checked config used above - recommended-type-checked - to
use TypeScript type checking APIs.

If we were using non-type-checked rules contained in other configs exported by the plugin,
such as the recommended config, we would not need to provide this information.

plugins: ['@typescript-eslint'] : I don't know what the purpose of this line is. It
shouldn't be necessary and I have tested that the given ESLint configuration works fine
without it. But it doesn't do any harm and was contained in an example in the plugin's
documentation from which I adapted the above config. So I have kept it.

The overrides section ensures that the TypeScript parser options that we’ve had to
configure in order to support type-checked configs apply only to .ts and .tsx extensions
(from this excellent StackOverflow answer). Otherwise, if parser and parserOptions objects
had been at the top level, then running ESLint on the project would throw errors on .js files.

This is a problem as we have several .js config files including the .eslintrc.js itself, so
there will be linting errors. We can avoid these errors by using the override.

ESLint Setup for Tailwind

If your app uses Tailwind, modify the config as follows:

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 13/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

1. On the terminal, in app's root folder, run npm install --save-dev eslint-plugin-
tailwindcss

2. In ESLint config, add "plugin:tailwindcss/recommended" to the END of extends:

{
"extends": ["next/core-web-vitals", ..., "plugin:tailwindcss/recommended"],

3. In the ESLint config, add "tailwindcss" to plugins and add a rules object as shown
below:

{
"plugins": [..., "tailwindcss"],
"rules": {
"tailwindcss/classnames-order": "off"
},
}

4. If your app uses TYPESCRIPT, then also add "plugin:tailwindcss/recommended"


to inner extends inside overrides and duplicate the rules object inside overrides:

{
...
overrides: [
{
extends: ["next/core-web-vitals", ...,
"plugin:tailwindcss/recommended"],
rules: {
'tailwindcss/classnames-order': 'off',
},
}
}

In the Tailwind setup steps above, we have installed the package for the ESLint plugin for
Tailwind, eslint-plugin-tailwindcss, and used the config recommended provided by the
plugin.

eslint-plugin-tailwind provides some useful linting rules for Tailwind CSS classes used
in HTML or JSX/TSX markup. The biggest one for me is that if a class used in code is not a
Tailwind class, there would be a linting error. This makes sense as when I am using Tailwind,
I only use Tailwind-generated classes and do not define my own CSS classes.

The plugin also has a rule that checks that the sequence of Tailwind class names used in the
class or className attribute in markup follows a canonical ordering. But we installed
prettier-plugin-tailwindcss in our Prettier configuration above which also reorders

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 14/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

Tailwind class names. So we don’t need this rule in ESLint and it might conflict with what
Prettier does in our workflow.

We’ll turn this rule off, which is named tailwindcss/classnames-order, in the configuration
above by declaring the plugin in plugins object, then setting the rule to off in the rules
object.

ESLint Setup for Prettier

1. On the terminal run:

npm install --save-dev eslint-config-prettier

2. In ESLint config, add "prettier" to the END of extends:

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

3. If your app uses TypeScript, then also add "plugin:tailwindcss/recommended" to


the inner extends inside overrides also:

{
...
overrides: [
{
"extends": ["next/core-web-vitals", ..., "prettier"],
}
}

In the Prettier setup steps above, the config referenced as prettier is the name of the
NPM package eslint-config-prettier with eslint-config- deleted. The default export
from the package is an entire ESLint config object and this is the config we want to
use.

So in this case, we do not suffix the name prettier with /<name of config> as we have
done when referencing the named config core-web-vitals from package eslint-config-
next when we referenced is as next/core-web-vitals (see step 1 above).

This config switches off those rules in ESLint that conflict with the code formatting done by
Prettier. This should be the last config in extends.

4. Create .eslintignore in the project root. It doesn't need to have any content for now,
but will come in handy in the future if ever you need to add folders or files that should
be ignored by ESLint (see the final section of this post for an example).

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 15/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

Set Up Stylelint
Stylelint is a linter for CSS and SCSS stylesheets.

If you are using SCSS and NOT Tailwind, then set up Stylelint by following the instructions
below. This set up will work for both CSS and SCSS files:

1. On the terminal in project root run this command:

npm install --save-dev sass

Next.js has built-in SASS/SCSS support (so the Webpack config knows how to handle
.scss and .sass files). But you still need to install a version of the sass package
yourself, which is what we did above.

2. Next, install packages for Stylelint and its rule configs:

npm install --save-dev stylelint stylelint-config-standard-scss stylelint-


config-prettier-scss

Of these three packages:

stylelint is the linter.

stylelint-config-standard-scss is a Stylelint config that provides linting rules.


It uses the Stylelint plugin stylelint-css and extends configs stylelint-config-
standard which defines rules for vanilla CSS, and stylelint-config-recommended-
scss which defines SCSS specific rules. As a result, extending from this one
config is enough to get linting support for both CSS and SCSS files.

stylelint-config-prettier-scss extends stylelint-config-prettier and turns off


those Stylint rules that conflict with Prettier's code formatting. This should be
declared last in extends: array in .stylelintrc.json (as shown below).

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 16/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

3. Now, create .stylelintrc.json in project root with the following contents:

{
"extends": [
"stylelint-config-standard-scss",
"stylelint-config-prettier-scss"
],
"rules": {
"selector-class-pattern": null
}
}

The "extends" section declares the two Stylelint configs whose NPM packages we
installed in the previous step.

The "rules" section is used to configure stylints rules. Here you can turn on or off, or
configure the behavior of, individual Stylelint rules.

You can turn off a rule by setting it to null, as I have done for "selector-class-pattern". I
turned it off because it insists on having CSS classes in the so called kebab case (for
example, .panel-quiz instead of .panelQuiz). I find it inconvenient for various reasons so I
turned it off.

4. Next, create .stylelintignore in the project root with the following contents:

styles/globals.css
styles/Home.module.css
coverage

I created this file so that the two stylesheets generated by the Next.js CLI which do not
comply with the linting rules can get ignored (there might be a better way of doing this
but this works for me). Also, files in coverage folder do not need to be linted and would
likely throw up errors.

Set Up package.json Scripts


1. The most important script is "build". The default command for this script, next build,
runs ESLint but not Prettier or (if you are using SCSS) Stylelint. So modify it in
package.json file as follows:

If your app uses Tailwind, then:

{
"scripts": {
"build": "prettier --check . && next build",
...

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 17/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

Otherwise, if your app uses SCSS, then:

{
"scripts": {
"build": "prettier --check . && stylelint --allow-empty-input \"**/*.
{css,scss}\" && next build",
...

With this tweak to the existing build script, we can run npm run build either locally or in a
CI/CD pipeline and it will fail not only on ESLint failure (this was the case before) but also on
Prettier formatting or Stylelint failure.

Indeed if you deploy your app to Vercel, the default pipeline there also calls npm run build.
So when I introduced an error in one of my stylesheets, then deployed to Vercel, I got the
following Stylelint error during deployment:

Note that I used the --check flag with prettier in the script (that is, I used the command
prettier --check .). This runs Prettier in check mode, so it only checks for correct
formatting and does not change the formatting.

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 18/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

I did this because the build script is what Vercel's deployment pipeline calls by default to
build the code, and I don't want formatting to change during a CI build (nor do I want to tinker
with Vercel defaults unless I absolutely have to).

To run Prettier locally to actually format the codebase, I define a separate build:local
script which is same as build but runs Prettier without the --check flag, as well as a
separate format script just to format with Prettier (but not build). These are set up below.

2. Set up the "format" script in your package.json. This formats the codebase with
Prettier and comes in handy every now and then:

{
"scripts": {
...
"format": "prettier --write ."

3. I recommend setting up a build:local script as follows:

If your app uses Tailwind, then:

"build:local": "prettier --write . && next build"

Otherwise, if your app uses SCSS, then:

"build:local": "prettier --write . && stylelint --allow-empty-input \"**/*.


{css,scss}\" && next build"

Since we cannot format the code with Prettier prior to executing next build in the existing
build script (for reasons described above), we can use this script locally to format code then
lint and build in one go.

Set Up lint-staged
lint-staged is a package that you can use to run formatting and linting commands on staged
files in a Git repo. Staged files are those that have been added to the Git index using git
add .. These are the files that have changed since the last commit and will get committed
when you next run git commit.

Husky is the typical choice in Node.js packages for registering commands to run in Git
hooks. For example, registering the command npx lint-staged with Husky to run in the Git
pre-commit hook means lint-staged will run automatically whenever you execute git
commit.

At that time, the formatter (Prettier) and linters (ESLint or Stylelint) that have been configured
to run in the lint-staged configuration file will run on the staged files. If there are any errors
during formatting checks or linting, the commit will fail.

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 19/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

Whenever git commit fails due to linting errors, we can fix those, then run git add . and
git commit again. Thus code only ever gets into the repo after it has been consistently
formatted and verified to be free of linting errors. This is particularly advantageous in a team
setting.

I prefer to only run prettier --check . on staged files. In particular, I do not change
formatting of staged files and do not lint during a commit, for the following reasons:

Reason for not formatting code: I almost always build and test my code before
committing. Any code formatting should have happened prior to or during this local build and
test.

I find the idea that code going into my repo should change automatically just as it is being
committed after I have ascertained that any code changes are good to go, a little bit
unappealing.

Reason for not linting code: With TypeScript code, the compiler can catch a huge number
of issues in code. The additional linting rules provided by eslint-typescript/eslint-
plugin only supplement the checks made by the TypeScript compiler. So if I am linting code
in staged files at commit time, I should build as well (so that the TypeScript compiler runs).

But building can be very time consuming on a large codebase. Besides, I almost always
build and test (because of the way scripts in package.json have been set up above).
Because of this, I don’t feel the need to repeat the lint and build process on staged files.

So, my personal preference is only to check for formatting on staged files, and neither
reformat nor lint the code. This prevents inconsistently formatted code from getting into the
Git repo where inconsistent formatting would make comparisons between different versions
of the same file difficult.

So now, set up lint-staged and Husky as follows:

1. Install the lint-staged package:

npm install --save-dev lint-staged

2. Create lint-staged.config.js in project root with the following contents:

/* eslint-env node */
const path = require('path');
const formatCommand = 'prettier . --check';

module.exports = {
'*': formatCommand,
};

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 20/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

3. Install the Husky NPM package.

npm install --save-dev husky

4. Run the following on the terminal in app root to configure Husky to run lint-staged
whenever git commit runs (in Git's pre-commit hook):

npx husky init


echo "npx lint-staged" > .husky/pre-commit

You should now have a file .husy/pre-commit in your app's folder with only one line:
npx lint-staged.

Set UP VS Code Extensions


If you use VS Code as your code editor, you can install the following VS Code extensions to
provide linting and formatting on file save and syntax highlight on linting errors:

ESLint extension

Prettier extension

Stylelint extension (if you're using SCSS and not Tailwind)

TaliwindCSS extension (if you are using Tailwind and not SCSS)

Put the following in a settings.json file in the .vscode folder in the project (you can of
course put these settings in you User Preferences file also. You can access it from
Command Palette Ctrl + P).

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 21/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

{
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"stylelint.validate": ["css", "scss"],
"editor.formatOnSave": true
}

As they’re set up, the extensions will lint and format on Save.

Final Checks and Troubleshooting


Now it’s time to build and commit:

npm run format


npm run build
git add .
git commit -m "fix: set up linting and formatting"

Building and committing is a good sanity check for the setup we just did.

If anything had not been set up correctly, you might get errors either during build or at
commit.

If you already had some code in the project, then there might be a few errors when you
commit. Typically, these can be resolved by:

Adding folders or files to one of the *ignore files. For example, I already had some
code in my project with Storybook installed. So I had to add folders .storybook and
storybook-static to each of .stylelintignore, .eslintignore and
.prettierignore as all three tools complained about them.

stories
storybook-static

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 22/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

Adding plugins for specific file types. For example, I had Gherkin .feature files in my
project to describe integration tests. Prettier couldn't format these. So I added the
prettier-plugin-gherkin by simply running:

npm install prettier-plugin-gherkin --save-dev

Note that usually it is enough to install the package for a Prettier plugin for Prettier to
locate it and additional configuration is not required.

Likewise, ESLint complained when it encountered .cy.ts files containing Cypress


interaction tests for my app. To resolve this linting error, I installed the NPM package
for Cypress ESLint plugin and configured it as described here (unlike Prettier, to get
this ESLint package to work, some configuration was required).

The typescript config might be too strict and there might be a lot of errors when you
build, such as:

If you do not want to fix individual errors in your existing codebase, and they are too
many to disable specific rules at error locations using ESLint comments (see below),
then the simplest solution would be to disable the @typescript-eslint/recommended-
type-checked config by commenting it out in .eslintrc.js and uncommenting
@typescript-eslint/recommended which is less strict.

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 23/24
12/1/24, 12:09 PM How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js

Sometimes it is safe to turn off a linting rule at a specific line or for a whole file. While I
am always wary of doing this, in a (deliberately bad) experimental code file, I had many
instances of an error that VS Code ESLint extension pointed. This was not caught
before but was now being pointed out because strict TypeScript linting rules had been
enabled:

So I pressed Ctrl + . to Show Code Actions (I could instead have clicked the yellow
lighbulb icon shown next to the issue), then selected “Disable @typescript/no-non-
null-assertion for the entire file”.

This placed the comment /* eslint-disable @typescript-eslint/no-non-null-


assertion */ on top of my file to disable all instances of that particular error within the
file:

https://www.freecodecamp.org/news/how-to-set-up-eslint-prettier-stylelint-and-lint-staged-in-nextjs/ 24/24

You might also like