TutorialsApr 22, 202510 min read

Add a linting and formatting workflow to your CI/CD pipeline using Eslint and Prettier

Daniel Efe

Front-end Developer

Developer B sits at a desk working on an intermediate-level project.

Linters and formatters offer developers a way to address misaligned brackets, inconsistent naming conventions, or buggy code being committed. Using these tools, developers can focus their efforts on building highly maintainable and scalable projects.

Eslint and Prettier are two powerful tools for linting and formatting. Eslint is a static code analysis tool that checks JavaScript code for irregular patterns and problems while enforcing coding conventions. Prettier is an opinionated multi-language code formatter that ensures consistent styling while improving overall code readability. Adding both tools to your project workflows eliminates inconsistent styles and coding issues.

In this tutorial, you will learn how to set up Eslint and Prettier in your project. You’ll then learn to automate code quality enforcement with CircleCI, ensuring consistent coding conventions and styling across your team.

Prerequisites

To successfully follow along with this tutorial, you will need:

  1. Node.js 18.17 or above
  2. A CircleCI account
  3. A GitHub account

Setting up the project and version control

To set up a complete linting and formatting workflow with Eslint and Prettier, your project must first be version-controlled with Git and pushed to a GitHub repository.

Note: This tutorial uses a weather app built with vanilla JavaScript as its example project. You can either follow along with this project or use another project. The steps in this tutorial can also work for frameworks and libraries.

To get started, clone the weather application from the GitHub repository:

git clone https://github.com/CIRCLECI-GWP/linting-and-formatting-workflow-circleci
cd Weather-application
git checkout starter-branch

Next, follow the steps outlined in the linked blog post to initialize Git and push your project to a GitHub repository.

Installing and configuring Eslint and Prettier

With your project version controlled with Git and pushed to a GitHub repository, it is time to install and configure Eslint and Prettier.

To get started, install Eslint by running the following command in your terminal:

npm init @eslint/config@latest

This will prompt you to select what you want to use Eslint for. Since our focus is to search for syntax issues and potential problems, select the To check syntax and find problems option.

Eslint prompt

The installation process will take a couple of minutes. Once completed, an eslint.config.mjs file will be added to your project directory.

Eslint file

Open the eslint.config.mjs file and replace its content with this:

import { defineConfig } from 'eslint/config'
import globals from 'globals'

export default defineConfig([
    {
        files: ['**/*.{js,mjs,cjs}'],
        languageOptions: {
            globals: globals.browser,
        },
        rules: {
            eqeqeq: 'error',
            'no-var': 'error',
            'prefer-const': 'warn',
            'no-global-assign': 'error',
            'no-param-reassign': 'warn',
            complexity: ['warn', { max: 16 }],
            curly: 'error',
            'no-debugger': 'error',
        },
    },
])

This configuration sets up basic linting rules to help maintain clean and consistent JavaScript code.

Note: This tutorial uses only basic rules. You can customize them if your project requires it.

With Eslint successfully configured, your next step is to install Prettier. In your terminal, run:

npm install --save-dev --save-exact prettier

Next, create a .prettierrc file in your project directory. You can either do this manually or by running:

node --eval "fs.writeFileSync('.prettierrc','{}\n')"

Update your .prettierrc file with this configuration:

{
    "trailingComma": "es5",
    "tabWidth": 4,
    "semi": false,
    "singleQuote": true,
    "printWidth": 50,
    "bracketSpacing": true,
    "arrowParens": "always",
    "endOfLine": "lf"
}

This code shows a Prettier configuration setup with basic rules:

  • The trailingComma rule adds trailing commas where valid, such as in objects and arrays.
  • The tabWidth rule specifies the number of spaces per indentation level.
  • The semi rule disables semicolons at the end of statements
  • The singleQuote rule enforces the use of single quotes instead of double quotes for strings.
  • The printWidth rule sets the maximum line length before Prettier wraps the code.
  • The bracketSpacing rule adds spaces between brackets in object literals.
  • The arrowParens rule includes parentheses around a sole arrow function parameter. The endOfLine rule enforces the use of Line Feed (LF) for line breaks.

Next, create a .prettierignore in your project directory to ignore files you do not want Prettier to format. You can either do this manually or by using the following command:

node --eval "fs.writeFileSync('.prettierignore','# Ignore artifacts:\nbuild\ncoverage\n')"

Update your .prettierignore file, with the following paths to ignore:

# Ignore artifacts:
build
coverage
node_modules
package-lock.json
package.json

Finally, to make Eslint run alongside Prettier without conflicts, install the necessary packages by running the following command in your terminal:

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

Upon successful installation, update your eslint.config.mjs file with the following code:

import prettierPlugin from 'eslint-plugin-prettier'

        plugins: {
            prettier: prettierPlugin,
        },

Running Eslint and Prettier locally

Having Eslint and Prettier installed and configured in your project, you can now run both tools to check and fix linting and formatting issues.

To do this, start by running Eslint locally using the following command:

npx eslint .

The above command will run checks on all files in your project and report any issues that go against the rules set in your eslint.config.mjs file.

Run Eslint

To fix all issues highlighted in your Eslint run, enter the following command in your terminal:

npx eslint . --fix

Once issues are successfully fixed, you will get no report in your terminal.

Fix Eslint

Next, check if your files are correctly formatted. You can do this using the following command:

npx prettier --check .

This will check your project files that have formatting issues.

Run Prettier

To automatically fix all issues detected by Prettier, enter the following command in your terminal:

npx prettier --write .

There you have it! You have successfully run Eslint and Prettier to check for linting and formatting issues, and also successfully fixed detected issues.

You can take the entire process further by ensuring linting and formatting rules are strictly adhered to before your code is committed to a GitHub repository. A perfect tool for this purpose is Husky.

To setup Husky in your project, start by installing it using the following command:

npm install --save-dev husky

Next, initialize Husky for your project using the command:

npx husky init

This command will create a .husky folder at the root of your project. Inside this folder, there will be a pre-commit file.

To enable your project to adhere to your specified Eslint and Prettier rules before each commit, navigate to your pre-commit file inside your .husky folder and replace its contents with the following code:

npx eslint . --fix && npx prettier --write .

Finally, commit and push your project to GitHub. If linting and formatting errors are detected, Husky will ensure they are fixed before committing your code.

Note: In situations where Eslint and Prettier encounter errors they can’t fix, the commits will be blocked. To bypass these errors and allow successful commits, you can use the “git commit –no-verify” command.

Automating Eslint and Prettier in CircleCI

Automating linting and formatting process ensures that your code adheres to your linting and formatting rules every time you push changes to GitHub or create a pull request. You can achieve this by integrating a CI/CD pipeline, with CircleCI automating these tasks in your project.

To integrate CircleCI, start by creating a .circleci folder at the root of your project. Within this folder, create a config.yml file where you will write your configurations.

In your config.yml file, add the following scripts:

versions: 2.1

jobs:
    lint:
        docker:
            - image: cimg/node:18.20.0
        steps:
            - checkout
            - run:
                  name: Install dependencies
                  command: npm ci
            - run:
                  name: Run Eslint
                  command: npx eslint .
            - run:
                  name: Check Prettier Formatting
                  command: npx prettier --check .

workflows:
    version: 2
    lint-workflow:
        jobs:
            - lint

The above configuration runs inside a Docker container using the cimg/node: 18.17 image to ensure a consistent Node.js environment. It then installs the necessary dependencies using npm ci, and runs Eslint and Prettier checks with npx eslint . and npx prettier —check ., respectively.

The lint job defined within the workflow section, automates the entire process and triggers a pipeline build whenever changes are pushed to GitHub.

Commit and push the changes to GitHub.

Next, go to CircleCI and log into your account.

Navigate to your project’s dashboard, search for your project repository, and click Set Up Project.

CircleCI project setup

Enter the name of the branch that contains your .circleci folder (this is your main branch), and click Set Up Project to trigger a pipeline build.

CircleCI branch name

With everything properly configured, your pipeline should run successfully on CircleCI.

CircleCI build success

You can click on the lint job to view pipeline details.

CircleCI lint details

Ensuring code quality in pull request

Ensuring code quality and consistent formatting should not be the responsibility of individual developers alone, but rather a shared goal across entire software development teams. For this reason, repository administrators can enforce specific linting and formatting conditions that must be met before changes are merged into key branches, such as main.

One effective way to do this is by enabling GitHub branch protection rules. These rules will mandate CircleCI workflows like your lint job to pass before pull requests can be merged.

To begin enforcing code quality and formatting in pull requests, log into your GitHub account.

Next, navigate to your repository, select your project repository (which in this tutorial is weather-application), and click on the Settings tab.

Repository settings

Next, scroll to the code and automation section and click Branches.

Code and automation section

This will open up Branch protection rules. Click on Add branch ruleset.

Add branch ruleset

Next, you will be asked to enter a Ruleset name, choose any name of your choice. Also, set Enforcement status to active.

Ruleset name

Scroll to the Target section, click on Add target > Include by pattern, followed by the name of your target branch (which in this case is your main branch). Then, click Add Inclusion pattern.

Target section Once done, scroll down to the Branch rules section. Select Require status check to pass > Add checks. In Add checks, search for your CircleCI lint job/workflow and select it.

Branch rules

Finally, scroll down and click on the Create button to create your ruleset.

There you have it! You just succeeded in setting GitHub branch protection for your project.

Testing Github branch protection

Now that you have successfully setup Github branch protection on your project, you can test to see its effectiveness by creating a branch and deliberately violating linting and formatting rules to see what happens upon merging.

To do this, start by creating a new Github branch from your terminal:

git checkout -b test-lint-check

Next, introduce intentional changes that violate Prettier rules in your weather.css file:

body {
    background: linear-gradient(rgba(10, 10, 10, 0.7), rgba(10, 10, 10, 0.7)),url(./image/malik-noman-GYKl2HLVTlQ-unsplash.jpg);
    background-position: center;
    background-size: cover;
    background-repeat: no-repeat;
    width: 100%;
    height: 100%;
    font-family:
        -apple-system, BlinkMacSystemFont,
        'Segoe UI', Roboto, Oxygen, Ubuntu,
        Cantarell, 'Open Sans', 'Helvetica Neue',
        sans-serif;
}

The line background: linear-gradient(rgba(10, 10, 10, 0.7), rgba(10, 10, 10, 0.7)),url(./image/malik-noman-GYKl2HLVTlQ-unsplash.jpg); from our above code breaks the Prettier printWidth rule by exceeding the default maximum line length before wrap.

Commit and push the changes to your test-link-check branch by entering the following into your terminal:

git add .
git commit -m "Test: Lint check"
git push origin test-lint-check

Note: Pushing code that violates your Prettier formatting rules will trigger a CircleCI build where the lint job will fail. This behavior shows that CircleCI is actively checking code quality for all branches.

Next, head over to GitHub and open a Pull Request from your test-lint-check branch into your main branch.

Open pull request

Since GitHub branch protection is active, merging your test-lint-check branch into main will fail.

Merging failed

To successfully merge the branch with main, revert the changes that violated your linting and formatting rules.

Conclusion

In this tutorial, you learned how to set up and configure Eslint and Prettier, running both tools to check for linting and formatting errors. You also learned how to set up Husky to enforce code quality before commits are made. You finished by automating the entire process using CircleCI and ensuring code quality on Pull Requests.

Moving on, endeavor to integrate all you have learned on both new and existing projects. You can view the complete code for this tutorial on GitHub.


Daniel Efe is a front-end developer and technical writer with expertise in JavaScript, React, and technical documentation. Daniel specializes in building web applications and creating accessible, comprehensive content designed to educate developers across all skill levels.

Copy to clipboard