<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vanessa082</title>
    <description>The latest articles on DEV Community by Vanessa082 (@vanessa082).</description>
    <link>https://dev.to/vanessa082</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1374272%2Fd2449b3f-59ba-4f79-b921-847875179605.png</url>
      <title>DEV Community: Vanessa082</title>
      <link>https://dev.to/vanessa082</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vanessa082"/>
    <language>en</language>
    <item>
      <title>Setting up ESLint in my Next.js + TypeScript project to keep code clean, consistent, and bug-free—a must for writing like a pro!</title>
      <dc:creator>Vanessa082</dc:creator>
      <pubDate>Tue, 13 May 2025 11:09:55 +0000</pubDate>
      <link>https://dev.to/vanessa082/setting-up-eslint-in-my-nextjs-typescript-project-to-keep-code-clean-consistent-and-bug-free-a-4boe</link>
      <guid>https://dev.to/vanessa082/setting-up-eslint-in-my-nextjs-typescript-project-to-keep-code-clean-consistent-and-bug-free-a-4boe</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe9610wm8hk8svayhpfdr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe9610wm8hk8svayhpfdr.png" alt="Image description" width="800" height="670"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I guess you're reading this in the same shoes I found myself in before writing this article. I decided to document my findings because of how hard it was. Still, it was fun to set up ESLint for my next project through its documentation and understanding what is going on, especially with the new changes. For those who do not know what ESLint is, I've got you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eslint&lt;/strong&gt;&lt;br&gt;
If you have ever used a configured linters file, and how it works, you will understand better will I mean by ESLint is an advanced linting configuration that helps you to write cleaner and clearer code. It identifies and reports bugs, making your code more consistent and helping you follow best practices. In short, you use ESLint to set rules for your code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rules&lt;/strong&gt;&lt;br&gt;
Being the core concept in ESLint, rules agree on what you have done that is valid and also let you know what needs to be done, providing suggestions without changing the application's logic, known as Rule fixes. You can create custom rules. Also note that ESLint has built-in rules, some of which come as Plugins. These plugins include rules, configurations, processors, and languages&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration file&lt;/strong&gt;&lt;br&gt;
ESLint configuration files contain your project's ESLint configurations. NPM can also share these configurations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parser&lt;/strong&gt;&lt;br&gt;
A parser in computer science is part of the compiler; it is responsible for breaking down code into human human-readable language for the computer. In ESLint, a parser converts code into an abstract syntax tree.&lt;/p&gt;

&lt;p&gt;With all these, there is the Eslint Custom Processors that draws JavaScript from other files for Eslint to lint the code. Also, not forgetting the Formatter in charge of the appearance&lt;/p&gt;

&lt;p&gt;With all these in mind, let's move to real business. Firstly, I will be using pnpm as my installer&lt;/p&gt;

&lt;p&gt;Start or bootstrap the next project.&lt;/p&gt;

&lt;p&gt;I will be using pnpm as my package manager&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-next-app@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;next,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpm add --save-dev eslint @eslint/js typescript typescript-eslint @next/eslint-plugin-next
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your package.json will look something like this, where the dev dependencies are&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "mytest",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
  },
  "dependencies": {
    "@next/eslint-plugin-next": "^15.3.2",
    "lucide-react": "^0.508.0",
    "next": "15.3.2",
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  },
  "devDependencies": {
    "@eslint/eslintrc": "^3",
    "@eslint/js": "^9.26.0",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "eslint": "^9.26.0",
    "eslint-config-next": "15.3.2",
    "globals": "^16.1.0",
    "typescript": "^5",
    "typescript-eslint": "^8.32.0"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, in your generated eslint.config.mjs, do the following configurations. We will start our configuration, but first, you have to note that Next has an existing plugin in the configuration that tracks common issues, which we installed above.&lt;/p&gt;

&lt;p&gt;Construct the __dirname. This is because in Commonjs, Node gives you the dirname since it is not done in modules, we have to recreate it by converting the&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import.meta.url

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;into an absolute file path by using.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const __filename = fileURLToPath(import.meta.url);  
// → turns this file’s URL into the real file path on your disk  
const __dirname  = dirname(__filename);  
// → strips off the filename, leaving just the folder path  

// Tell FlatCompat where to look for configs
const compat = new FlatCompat({  
  baseDirectory: __dirname  
});  
// → now compat knows your project’s root folder and can find 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;shareable configs there&lt;br&gt;
With it done, in the defineConfig method, pull in Next.js’s built-in best-practice rules add rules from plugin:@next/next/core-web-vitals&lt;br&gt;
and plugin:@next/next/typescript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; …compat.extends(“next/core-web-vitals”, “next/typescript”)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, define our global ignores and environments in the config file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; {
    ignores:
      [
        ".next/**",
        ".env",
        "node_modules",
        "public/**",
        "next.config.js",
        "postcss.config.js"
      ]
  },
  {
    languageOptions: { globals: { ...globals.browser, ...globals.node } }
  } 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can set up rules and plugins&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    plugins: {
      js,
      "@next/next": pluginNext,
      "@typescript-eslint": tsPlugin,
      tailwindcss: tailwind,
    },
    files: ["**/*.{js,mjs,cjs,jsx,ts,tsx}"],
    rules: {
      ...js.configs.recommended.rules,
      ...pluginNext.configs.recommended.rules,
      ...pluginNext.configs["core-web-vitals"].rules,
      ...tsPlugin.configs.recommended.rules,
      ...tailwind.configs["flat/recommended"].rules,

      "quotes": ["warn", "double", { avoidEscape: true }],
      "semi": ["warn", "always"],
      "indent": ["warn", 2],
      "no-multiple-empty-lines": ["error", { max: 1 }],
      "eol-last": ["warn", "always"],

      "no-unused-vars": "off",
      "@typescript-eslint/no-unused-vars": ["warn"],
      "no-undef": "off",
    },
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how the complete file will look&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import { FlatCompat } from '@eslint/eslintrc'
import { defineConfig } from "eslint/config";
import { fileURLToPath } from "url";
import { dirname } from "path";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename)

const compat = new FlatCompat({
  baseDirectory: __dirname
})

export default defineConfig([
  ...compat.extends("next/core-web-vitals", "next/typescript"),
  {
    ignores:
      [
        ".next/**",
        ".env",
        "node_modules",
        "public/**",
        "next.config.js",
        "postcss.config.js"
      ]
  },
  {
    languageOptions: { globals: { ...globals.browser, ...globals.node } }
  },
  { files: ["**/*.{js,mjs,cjs,ts}"], plugins: { js }, extends: ["js/recommended"] },
  { files: ["**/*.{js,mjs,cjs,ts}"], languageOptions: { globals: globals.browser } },
  {
    rules: {
      "no-unused-vars": ["warn"],
      "no-undef": ["warn"],
      "quotes": ["warn", "double", { "avoidEscape": true }],
      "semi": ["warn", "always"],
      "indent": ["warn", 2],
      "class-methods-use-this": "warn",
      "eol-last": ["warn", "always"],
      "no-unused-expressions": ["warn"],
      "no-multiple-empty-lines": ["error", { "max": 1 }],
      "no-trailing-spaces": ["warn"],
      "no-useless-constructor": 0,
      "no-loop-func": 0,
    }
  },

  js.configs.recommended,
  tseslint.configs.recommended,
]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, you can run your script, and it works.&lt;/p&gt;

&lt;p&gt;Conclusion&lt;br&gt;
I would say the are many ways to configure ESLint in projects, and you might not find my approach as great as it may be to me, but I would love to hear from you. Every configuration depends on your project requirements.&lt;/p&gt;

&lt;p&gt;References&lt;br&gt;
&lt;a href="https://nextjs.org/docs/app/api-reference/config/eslint#migrating-existing-config" rel="noopener noreferrer"&gt;Next.js documentation on the ESLint plugin&lt;/a&gt;, &lt;a href="https://typescript-eslint.io/getting-started/" rel="noopener noreferrer"&gt;TypeScript ESLint&lt;/a&gt;, &lt;a href="https://eslint.org/docs/latest/use/integrations#editors" rel="noopener noreferrer"&gt;Eslint official documentation&lt;/a&gt;&lt;/p&gt;

</description>
      <category>eslint</category>
      <category>webdev</category>
      <category>typescript</category>
      <category>nextjs</category>
    </item>
  </channel>
</rss>
