First thing to note is that the eslint.config.js file should be at the root level of your project; you can target specific files and folders within the project structure from this one central configuration if need be i.e. in a monorepo.

The "extends" property does not exist under the new ESLint flat configuration schema, as per the 'Configuration Objects' specified in their documentation. You can directly import a configuration and declare it within the new eslint.config.js, however if that configuration extends other configurations this won't work - I can't see your '@ui' configuration definition so I have assumed in my code block that it does not extend configurations within itself (if it does, see blog link below on using @eslint/eslintrc 'compat' to bring in such configurations).

The "parserOptions" is also not a top-level property under the new schema and falls inside the 'languageOptions' property.

    // eslint.config.js at the project root
    import ParserTypescriptEslint from '@typescript-eslint/parser'
    import PluginImport from 'eslint-plugin-import';
    import PluginJest from 'eslint-plugin-jest';
    import UIConfig from 'ui-config-path';
    import globals from 'globals';
    
    export default [
      UIConfig,
      {
        files: [ "// Specify the files you wish to target with this configuration" ],
        languageOptions: {
          ecmaVersion: 2021,
          sourceType: 'module',
          globals: {
            ...globals.browser,
            ...globals.es2021,
          },
          parser: ParserTypescriptEslint,
          parserOptions: {
            project: ["./tsconfig.json"],
            tsconfigRootDir: __dirname,
          },
        },
        plugins: {
          import: PluginImport,
          jest: PluginJest
        },
        rules: {
          "jest/no-deprecated-functions": "off"
        },
        settings: {
          "import/resolver": {
            ...PluginImport.configs.typescript.settings['import/resolver'],
            typescript: {
              project: ["tsconfig.json"],
            },
          },
        },
        
      }
    ]

If you have multiple sub-configurations that you wish to use for different folders/systems - React, Express, Jest, etc - then you can write those configurations following the new schema and spread them into the main eslint.config.js file. This is a snippet of my main eslint.config.js that uses several different sub-configurations.

    import { EslintConfig, ConfigPrettier } from '@packages/eslint-config';
    import { EslintConfigReact } from '@packages/eslint-config-react';
    import { EslintConfigReactTest } from '@packages/eslint-config-react-test';
    import { EslintConfigExpress } from '@packages/eslint-config-express';
    
    export default [
      ConfigPrettier,
      {
        ignores: ['**/node_modules', '**/dist', '**/build', '**/__snapshots__', '**/mocks', '**/coverage'],
      },
      {
        // Client - React
        files: [
          'apps/*/frontend/**/*.ts',
          'apps/*/frontend/**/*.tsx',
          'apps/*/frontend/**/*.jsx',
          'apps/*/frontend/**/*.js',
        ],
        languageOptions: { ...EslintConfig.languageOptions, ...EslintConfigReact.languageOptions },
        plugins: { ...EslintConfig.plugins, ...EslintConfigReact.plugins },
        rules: { ...EslintConfig.rules, ...EslintConfigReact.rules },
        settings: { ...EslintConfig.settings, ...EslintConfigReact.settings },
      }
    ];

The following blog post was useful to me in setting up the new ESLint flat configuration in a monorepo structure: migration-eslint-to-flat-config

Answer from SS87 on Stack Overflow
🌐
ESLint
eslint.org › docs › latest › use › configure › configuration-files
Configuration Files - ESLint - Pluggable JavaScript Linter
If ignores is used without any ... configuration object. extends - An array of strings, configuration objects, or configuration arrays that contain additional configuration to apply....
🌐
ESLint
eslint.org › docs › latest › use › configure › migration-guide
Configuration Migration Guide - ESLint - Pluggable JavaScript Linter
You can also use the extends property to extend a shareable config. Shareable configs can either be paths to local config files or npm package names. In flat config files, predefined configs are imported from separate modules into flat config files.
Discussions

How to use new ESLint Configuration File syntax with extensions and TypeScript - Stack Overflow
As you can see, this current config extends an existing config that I have in my package.json called @ui/eslint-config and sets some things up related to TypeScript. I also need this to be able to lint JSX/TSX files. More on stackoverflow.com
🌐 stackoverflow.com
Change Request: Flat config extends
ESLint version HEAD What problem do you want to solve? Now that more folks are moving to ESLint v9 and flat config, a common complaint is that it's difficult to extend configs from plugins. Whe... More on github.com
🌐 github.com
13
November 7, 2024
What's the difference between plugins and extends in eslint?
By extending from a plugin config, we can get recommended rules without adding them manually. A plugin is a special eslint npm package, that provides additional rule definitions (rules), environments, processors and configs for different configurations of recommended / default rule values. The plugins property in .eslintrc.js ... More on stackoverflow.com
🌐 stackoverflow.com
Will the `"eslintConfig"` key in `package.json` files still work in ESLint v9?
Will the "eslintConfig" key in package.json files still work in ESLint v9? ... If "yes" to the above, will the data structure change to match the flag config changes? I'm assuming that this would have to be a "yes" considering that v8's extends key will no longer be a config option as of v9, ... More on github.com
🌐 github.com
3
5
🌐
ESLint
eslint.org › blog › 2025 › 03 › flat-config-extends-define-config-global-ignores
Evolving flat config with extends - ESLint - Pluggable JavaScript Linter
March 7, 2025 - The defineConfig() function allows you to specify an extends array in any object, and that array can contain objects, arrays, or strings (for plugin configs that follow the recommended approach).
🌐
ESLint
eslint.org › docs › latest › extend › ways-to-extend
Ways to Extend ESLint - ESLint - Pluggable JavaScript Linter
This page explains the ways to extend ESLint, and how these extensions all fit together. Plugins let you add your own ESLint custom rules and custom processors to a project. You can publish a plugin as an npm module. Plugins are useful because your project may require some ESLint configuration that isn’t included in the core eslint package.
🌐
ESLint
eslint.org › docs › latest › extend
Extend ESLint - ESLint - Pluggable JavaScript Linter
This section explains how you can bundle and share ESLint configuration in a JavaScript package.
Top answer
1 of 1
9

First thing to note is that the eslint.config.js file should be at the root level of your project; you can target specific files and folders within the project structure from this one central configuration if need be i.e. in a monorepo.

The "extends" property does not exist under the new ESLint flat configuration schema, as per the 'Configuration Objects' specified in their documentation. You can directly import a configuration and declare it within the new eslint.config.js, however if that configuration extends other configurations this won't work - I can't see your '@ui' configuration definition so I have assumed in my code block that it does not extend configurations within itself (if it does, see blog link below on using @eslint/eslintrc 'compat' to bring in such configurations).

The "parserOptions" is also not a top-level property under the new schema and falls inside the 'languageOptions' property.

    // eslint.config.js at the project root
    import ParserTypescriptEslint from '@typescript-eslint/parser'
    import PluginImport from 'eslint-plugin-import';
    import PluginJest from 'eslint-plugin-jest';
    import UIConfig from 'ui-config-path';
    import globals from 'globals';
    
    export default [
      UIConfig,
      {
        files: [ "// Specify the files you wish to target with this configuration" ],
        languageOptions: {
          ecmaVersion: 2021,
          sourceType: 'module',
          globals: {
            ...globals.browser,
            ...globals.es2021,
          },
          parser: ParserTypescriptEslint,
          parserOptions: {
            project: ["./tsconfig.json"],
            tsconfigRootDir: __dirname,
          },
        },
        plugins: {
          import: PluginImport,
          jest: PluginJest
        },
        rules: {
          "jest/no-deprecated-functions": "off"
        },
        settings: {
          "import/resolver": {
            ...PluginImport.configs.typescript.settings['import/resolver'],
            typescript: {
              project: ["tsconfig.json"],
            },
          },
        },
        
      }
    ]

If you have multiple sub-configurations that you wish to use for different folders/systems - React, Express, Jest, etc - then you can write those configurations following the new schema and spread them into the main eslint.config.js file. This is a snippet of my main eslint.config.js that uses several different sub-configurations.

    import { EslintConfig, ConfigPrettier } from '@packages/eslint-config';
    import { EslintConfigReact } from '@packages/eslint-config-react';
    import { EslintConfigReactTest } from '@packages/eslint-config-react-test';
    import { EslintConfigExpress } from '@packages/eslint-config-express';
    
    export default [
      ConfigPrettier,
      {
        ignores: ['**/node_modules', '**/dist', '**/build', '**/__snapshots__', '**/mocks', '**/coverage'],
      },
      {
        // Client - React
        files: [
          'apps/*/frontend/**/*.ts',
          'apps/*/frontend/**/*.tsx',
          'apps/*/frontend/**/*.jsx',
          'apps/*/frontend/**/*.js',
        ],
        languageOptions: { ...EslintConfig.languageOptions, ...EslintConfigReact.languageOptions },
        plugins: { ...EslintConfig.plugins, ...EslintConfigReact.plugins },
        rules: { ...EslintConfig.rules, ...EslintConfigReact.rules },
        settings: { ...EslintConfig.settings, ...EslintConfigReact.settings },
      }
    ];

The following blog post was useful to me in setting up the new ESLint flat configuration in a monorepo structure: migration-eslint-to-flat-config

🌐
Prateeksurana
prateeksurana.me › blog › difference-between-eslint-extends-and-plugins
What is the difference between extends and plugins in ESLint config
September 11, 2021 - Its job is to statically analyze and fix problematic patterns in your JavaScript code or code that doesn't adhere to some style guidelines that you would want to be followed throughout your whole project. The project owner can choose the rules they want to enforce via a configuration file .eslintrc.{js,yml,json} in the root directory of their project.
Find elsewhere
🌐
ESLint
eslint.org › docs › latest › extend › shareable-configs
Share Configurations - ESLint - Pluggable JavaScript Linter
To use a shareable config, import the package inside of an eslint.config.js file and add it into the exported array using extends, like this:
🌐
ESLint
eslint.org › docs › latest › use › configure
Configure ESLint - ESLint - Pluggable JavaScript Linter
Configuration Files - use a JavaScript file to specify configuration information for an entire directory and all of its subdirectories. This can be in the form of an eslint.config.js file which ESLint will look for and read automatically, or you can specify a configuration file on the command line.
🌐
Eslint
eslint.style › guide › config-presets
Shared Configurations | ESLint Stylistic
// Legacy config is no longer supported in v4+ // Please use v3.x if you need to use legacy config // We encourage you to migrate to flat config soon // .eslintrc.js module.exports = { extends: [ 'plugin:@stylistic/all-extends' ], rules: { // ...your other rules } }
🌐
GitHub
github.com › eslint › eslint › issues › 19116
Change Request: Flat config extends · Issue #19116 · eslint/eslint
November 7, 2024 - In flat configs, extends will not trigger any file loading. Instead, it will allow string identifiers for configs contained in plugins as well as objects. Here's a simple example: import js from "@eslint/js"; export default [ { plugins: { js }, files: ["**/*.js"], extends: ["js/recommended"], rules: { "prefer-const": "off" } } ];
Author   nzakas
🌐
Raul Melo
raulmelo.me › en › blog › migration-eslint-to-flat-config
Embrace the Future: Navigating the New Flat Configuration of ESLint · Raul Melo
July 20, 2023 - You no longer need to prefix the lib with eslint-config-*, and you also no longer need to do a default export. Like extends, plugins will follow the same principle: we need to import and reference them inside one of one config object: ... import jsdoc from "eslint-plugin-jsdoc"; /** @type {import('eslint').Linter.FlatConfig[]} */ export default [ { files: ["**/*.js"], plugins: { jsdoc, }, rules: { // Other rules...
Top answer
1 of 4
148

extends uses a config file which applies set of rules when you add that to the extends options. A plugin on the other hand provides you with a set of rules that you can individually apply depending on your need. Just having a plugin does not enforce any rule. You have to choose which rules you need. A plugin may provide you with zero, one, or more configuration files. If the plugin provides configuration file, then you can load that in your extends section after adding the plugin in the plugins section.

So essentially, plugins given you some rules that have been coded and you can choose which ones are relevant. It may also provide config files to apply rules that the authors think are logically grouped/relevant but providing a config file is not mandatory for a plugin. extends, on the other hand, provides you the ability to apply rules in bulk based on config file specifications.

Example Plugin - eslint-plugin-react

{
  "plugins": [
    "react"
  ],
  "extends": [
    "eslint:recommended",
    "plugin:react/recommended"
  ]
}

Example Config - eslint-config-google

{
  "extends": [
    "google"
  ]
}
2 of 4
51

In addition to shmit's good answer:

extends

is about extending configurations in general, not only plugins. Potential values are:

  • "eslint:recommended"
  • "eslint:all"
  • Shareable configuration from npm package (eslint-config-xxx or scoped name)
  • Plugin configuration from npm package (eslint-plugin-xxx or scoped name)
  • Another configuration file, like "./my/path/.eslintrc.js"

Plugin notation: plugin:<package name>/<configuration name>, e.g. for eslint-plugin-react:

Copy "extends": ["plugin:react/recommended"]

By extending from a plugin config, we can get recommended rules without adding them manually.

plugins

A plugin is a special eslint npm package, that provides additional rule definitions (rules), environments, processors and configs for different configurations of recommended / default rule values.

The plugins property in .eslintrc.js is merely a flag to enable a given plugin after installation with npm i. We now can refer to the plugin's rules, but have to set all rules values manually.

Think of plugins as a way to activate a plugin - to use its rules, you need to add the plugin once in the chain in every case.

plugins is not needed in your own config, if it is already defined in a configuration, that you extend from by extends.

Example:

eslint-plugin-react already contains plugins: [ 'react' ], hence this entry is not needed anymore in own config and plugin rules can be used directly.

🌐
GitHub
github.com › eslint › eslint › discussions › 18131
Will the `"eslintConfig"` key in `package.json` files still work in ESLint v9? · eslint/eslint · Discussion #18131
The main reason is that it's not generally possible in ESLint v9, like it was possible in ESLint v8, to write a config file in JSON format. For example, there is no longer a standard to resolve a shared config by name by specifying "my-config-module" in the extends field.
Author   eslint
🌐
Stack Overflow
stackoverflow.com › questions › 77061899 › how-to-extend-and-override-rules-config-in-eslint
How to extend and override rules config in ESLint?
{ "extends": ["next", "prettier"], "plugins": ["prettier", "@typescript-eslint", "unused-imports"], "rules": { "no-unused-vars": "off", "no-duplicate-imports": "off", "no-console": "warn", "no-return-await": "warn", "no-useless-return": "warn", "no-var": "warn", "react-hooks/exhaustive-deps": "off", "import/order": [ "warn", { "groups": ["type", "builtin", "external", "internal", "parent", "sibling", "index", "object"], "newlines-between": "always" } ], } } ./web.json (the config will be applied for web and extends from base.json)
🌐
GitHub
gist.github.com › randallreedjr › 40282968b6f39dc3f423dd3cf1106455
ESLint config file extending local configuration · GitHub
ESLint config file extending local configuration. GitHub Gist: instantly share code, notes, and snippets.
🌐
Next.js
nextjs.org › docs › app › api-reference › config › eslint
Configuration: ESLint | Next.js
2 weeks ago - Learn how to use and configure the ESLint plugin to catch common issues and problems in a Next.js application.
🌐
GitHub
github.com › eslint › eslint › discussions › 18377
Add more comprehensive examples of best practise eslint.config.js's for v9 migration · eslint/eslint · Discussion #18377
Some changes were easy like moving ... under globals). However, with extends and plugins blocks I had no idea is importing them necessary anymore or what's the recommend best practise. It seems eslint:recommended was moved to "@eslint/js".configs.recommended so this added to the ...
Author   eslint
🌐
Expo Documentation
docs.expo.dev › integrations › tools › using eslint and prettier
Using ESLint and Prettier - Expo Documentation
2 weeks ago - To set up ESLint in your Expo project, you can use the Expo CLI to install the necessary dependencies. Running this command also creates a eslint.config.js file at the root of your project which extends configuration from eslint-config-expo.
🌐
ESLint
eslint.org › blog › 2022 › 08 › new-config-system-part-2
ESLint's new config system, Part 2: Introduction to flat config - ESLint - Pluggable JavaScript Linter
August 5, 2022 - That one eslint.config.js file contains all of the configuration information for that run of ESLint so it dramatically reduces the disk access required as compared to eslintrc, which had to check each directory from the linted file location up to the root for any additional config files. Additionally, using a JavaScript file allowed us to rely on users to load additional information that their config file might need. Instead of extends and plugins loading things by name, you can now just use import and require as necessary to bring in those additional resources.