8 must-have ESlint plugins for your Node.js application

Using Eslint in your project is an easy way to improve productivity and reduce low-value, subjective code-style comments from pull requests. It will make your code consistent and easy for the next developer to read and we should always be optimising for readability.

Using some specific Eslint plugins will also prevent real bugs and security issues in TypeScript and JavaScript applications through static analysis.

Here I'll explain why it's so important to use ESLint in your application and I'll describe the plugins I always add to every new NodeJs application to massively improve code quality and consistency.

Why I use ESLint on every project

I use ESLint on all my professional work to ensure consistency for the entire team and to make sure we're writing a standard typescript/javascript in all files. Making it easier for other developers to understand our code quickly is one of the easiest ways to improve productivity in a development team.

I also use Eslint on all my personal projects because it's like having an additional senior dev watching my back every time I commit code. I make mistakes all the time when working alone so I need all the help I can get! Eslint plugins contain the experience of all the developers who spent the time writing rules. It would be silly to not use this knowledge.

Here's some details on the reasons you should use Eslint and all these awesome plugins.

Eliminating subjective arguments

Most ESLint rules are subjective code-style type rules. Once you lock in a setting for code-style then ESLint will enforce it. This is the key benefit for these types of stylistic rules. If you're getting lots of "nit" type comments in PRs just add an eslint rule to make them stop by having Eslint fix them for you automatically before you show the PR to colleagues.

If someone disagrees with a configured Eslint rule that's no problem - in fact these discussions should be welcomed because it shows the person cares about the code.

To resolve these rule change requests, just let the team vote and if the vote is successful the person that wants to change the rule can go ahead and change it BUT - they also have to make all the existing code compliant.

This usually isn't a large task with eslint auto-fixes or just search and replace.

Having consistency across your code base is important for readability, quality and onboarding new developers. They specific code styles used doesn't matter so much, most developers will just adjust in a few days or less as they jump across code bases.

But your rules should be internally consistent for the specific code base.

Preventing objective code smells

In addition to styles and code consistency some of these eslint plugins will objectively improve your product and prevent real bugs. They perform static analysis for specific libraries that even tooling like typescript won't detect.

The sonar plugin in particular has some interesting code smell detections worth trying out.

These types of rules are often objectively beneficial and should be configured on EXCEPT where they are redundant because something like typescript already covers them, they are too restrictive, or they're just not relevant to your code.

Learning and keeping up to date

When you activate all the plugins I list here you will have 100s of tests of your code on each linting run.

You effectively have expert JavaScript developers pair programming with you all day, suggesting the best way to write your software as you build it.

It's just not realistic to expect a single engineer to remember to apply all these rules to each commit. For newer developers seeing these rules can be a great way to learn good practices by following the explanations in documentation.

And the best thing is that these plugins are under active development so they will be updated as the JavaScript industry learns and improves.

The value you get from adding these eslint plugins to your project is equivalent to adding an additional dev and an additional QA to your team.

8 must have ESlint plugins

Hers's a list of the plugins I use on all my projects and I've added some additional notes about plugins I don't find useful.

1. eslint-plugin-unicorn

Eslint unicorn is just brilliant! It's a list of all kinds of rules to help with JavaScript projects.

Unicorn will remind you to use array.includes instead of some or find if you're working on a list of strings for example. There are too many awesome rules to list each here so check out their docs.

This plugin is a must have!

Unicorn is updated regularity and is a nice way to get lazy updates on what's happening in the JavaScript world. For example I recently learned about the node: scheme for being more explicit about importing Node.js libraries from unicorn.

import fs from 'fs'

// Vs

import fs from 'node:fs'

There are some rules in unicorn that I disable or change like abbreviations. For example you'll use abbreviations like "res" or "req" all over your controllers if you use NestJs or express. You will want to tell unicorn to ignore those.

Here are some of my disabled unicorn rules.

"unicorn/no-fn-reference-in-iterator": "off",
  "unicorn/no-array-for-each": "off",
  "unicorn/no-null": "off",
  "unicorn/consistent-destructuring": "off",
  "unicorn/no-array-reduce": "off",
  "unicorn/prefer-spread": "off",
  "unicorn/no-array-callback-reference": "off",
  "unicorn/consistent-function-scoping": "off",
  "unicorn/no-useless-undefined": "off",
  "unicorn/prevent-abbreviations": [
      "error",
      {
          allowList: { Param: true, Req: true, Res: true },
      },
  ],

2. eslint-plugin-import

This plugin will warn you if you do anything sketchy with module imports. If you use typescript make sure you add the recommended rules for typescript so you don't get conflicts.

extends: [
        "plugin:import/errors",
        "plugin:import/warnings",
        "plugin:import/typescript", // make sure you add this one for ts projects
    ],

Also remember to set the parser options for typescript

settings: {
        ["import/parsers"]: { "@typescript-eslint/parser": [".ts", ".tsx"] },
        ["import/resolver"]: {
            node: {
                extensions: [".ts"],
            },
        },
    },

Typescript will already find any unresolved modules for you but this plugin is still useful for consistency like forbidding named default imports.

3. @typescript-eslint/eslint-plugin

This plugin is a must have if you're using typescript in your project. Just make sure you set up the typescript parser correctly by following the instructions on their readme.

This is the bit of config I use

{
  parser: "@typescript-eslint/parser",
  parserOptions: {
    project: "tsconfig.json",
    sourceType: "module",
    ecmaVersion: "es2019",
  },

There are 50 rules or more here so you'll have to read the documentation yourself.

The default recommended rule set is excellent but if you're adding this to an existing project you might have too many errors. Disable the worst rules for now and work at refactoring out the issues.

There is a naming-convention rule that you should configure for your project and your organisation. It's worth getting familiar with this rule and setting it up instead of turning it off. Here is an example

"@typescript-eslint/naming-convention": [
            "error",
            {
                selector: "default",
                format: ["camelCase"],
            },
            {
                selector: "variable",
                format: ["PascalCase", "UPPER_CASE"],
                types: ["boolean"],
                prefix: ["is", "should", "has", "can", "did", "will"],
            },
            {
                selector: "variableLike",
                format: ["camelCase", "UPPER_CASE", "PascalCase"],
            },

            {
                selector: "parameter",
                format: ["camelCase"],
            },
            {
                selector: "memberLike",
                modifiers: ["private"],
                format: ["camelCase"],
                leadingUnderscore: "forbid",
            },
            {
                selector: "typeLike",
                format: ["PascalCase"],
            },
            {
                selector: "property",
                modifiers: ["readonly"],
                format: ["PascalCase"],
            },
            {
                selector: "enumMember",
                format: ["UPPER_CASE"],
            },
        ],

4. eslint-plugin-eslint-comments

This is a meta eslint plugin but very useful. It analysis the comments you can use to control how Eslint parser your code. This will help you have great comments that describe eslint directives like

/*eslint-disable no-undef */

In particular it will spot useless ignores that you leave behind from after you refactor something or when you forget to re-enable a rule. This is well worth adding to your project.

You might want to change the rule for eslint pairs so that it allows using Eslint disable comments for entire files. I find preventing complete file rule disabling is too restrictive.

"eslint-comments/disable-enable-pair": [
     "error",
     { allowWholeFile: true },
 ],

5. eslint-plugin-sonarjs

This plugin detects code smells like duplicate functions, duplicate string usage or switch statements with too many conditions.

One very interesting rule in SonarJS will try to prevent codeblocks that present too much cognitive complexity. This is a special Sonar specific measure that builds on cyclomatic complexity. There is more detail here: https://www.sonarsource.com/docs/CognitiveComplexity.pdf

There are too many rules to go through in this rule set but sonar's js plugin is really useful and you should check it out.

6. eslint-plugin-jest

The jest Eslint plugin is a really worthwhile addition to your code. I make so many mistakes in jest tests without it.

For example, did you know that you should always return asynchronous expects?

expect(myResult).resolves.toEqual(expected) // this is wrong
return expect(myResult).resolves.toEqual(expected) // this is correct

If you don't return you can get a hanging promise and an Jest test run that slows everything down.

Sometimes I accidentally do my assertion in the expects like this

expect(myResult === expected)

This doesn't error but it doesn't assert your test case as expected at all. You'll get passes!

The jest eslint plugin will prevent these very dangerous errors and much more.

7. eslint-plugin-nestjs-typed

Shameless plug here because I wrote this plugin. I use NestJs for all my backend web projects so I always add this plugin to my projects.

eslint-plugin-nestjs-typed does two things.

It will remind you of any injectable services that you're not providing in a module. It will do this statically instead of waiting for the nest js runtime.

If you use swagger it will prompt you to apply the correct decorators for most scenarios to ensure any code gen you run on the swagger will product correct models.

Check it out if you use nestjs!

8. eslint-plugin-promise

This plugin is useful for at least one rule. It forces you to always return a value from a promise or a then().

There is another rule here that enforces either async/await or then()/catch(). This could be useful at the start of a project to force one or the other.

Typescript and unicorn cover most of the other rules here so you might not need this one. I still recommend it.

Bonus: Interesting ESlint plugins for specific projects

eslint-plugin-lodash

Rules for lodash if you have lodash in your project. I use lodash very minimally these days so I don't use this plugin. If I do start to use lodash more often I would use the plugin again for sure.

eslint-plugin-no-secrets

This plugin detects strings that look like they could be secrets. This is a really clever plugin but I found that it was extremely sensitive and difficult to configure correctly. You might have a better experience with this though.

It's worth trying if it's that secrets are never in your app.

eslint-plugin-html

This plugin can lint JavaScript inlined into your html. I would only add this if I had lots of inline JavaScript in html files. This is unlikely in modern js applications but there is quite a bit of legacy JavaScript out there.

eslint-plugin-markdown

This plugin will parse code in your markdown files. This is useful if you were creating professional technical documentation or similar.

I have code snippets all over this blog but I still don't use this plugin anymore because vscode formats my code in markdown now.

ESlint Plugins to avoid

eslint-plugin-node

I haven't found massive value in these rules but I mostly use Node.js for web application development.

eslint-plugin-json

I don't use this plugin because vscode's JSON language features cover most of the rules already. I recommend using your IDE instead of this.

If most of your developers will be using an IDE of some kind you might be able to skip this plugin. If your devs are using text editors to write json then add this to your CI.

21