| | |

ESLint 11 🛡️ Shareable Configs — Extending community rule sets

⏱️ Estimated read: 10 min | |

A shareable config is an npm package that exports an ESLint configuration object or array. It packages a set of rules, plugins, parsers, and language options into a single dependency that a project can import and apply. The ESLint ecosystem has produced dozens of these packages—Airbnb’s style guide, Standard’s minimalist rules, Google’s readability-focused set, and the TypeScript-ESLint project’s recommended, strict, and stylistic tiers. Extending one is the difference between writing a configuration from scratch and adopting a set of rules that a community has already debated, tested, and maintained.

This chapter covers the shareable config package, the naming convention that makes it discoverable, the extends mechanism in the flat config, and the dependency rules that determine whether a config brings its plugins with it or expects the project to install them separately.

Key point: A shareable config is just an npm package that exports a config object or array. The eslint-config- prefix is a convention, not a requirement. The config’s peerDependencies declare the ESLint version it supports, and its dependencies declare the plugins and parsers it needs. The project that extends the config is responsible for installing the peer dependencies.


Why shareable configs exist

The debate problem. Every team that writes an ESLint configuration from scratch eventually debates the same questions: semicolons or no semicolons, single or double quotes, trailing commas or none, strict or permissive. A shareable config encodes a set of answers that a community has already settled on. Extending it replaces the debate with a decision: adopt the config or don’t, and if you don’t, pick a different one. The Node.js reference architecture document lists “minimizing what can be potentially divisive discussions” as the first benefit of using a pre-existing config .

The maintenance problem. A hand-written configuration accumulates rules over time. A new ESLint version introduces new recommended rules, a new TypeScript version introduces new syntax, and a new framework version introduces new patterns. A shareable config is maintained by its authors, and the project that extends it receives the updates when it bumps the dependency version. The Node.js document notes that “these configs can change over time” and recommends “time in your regular workflow to review these changes” .

The ecosystem problem. The ESLint documentation describes the extension mechanism as a first-class feature: “You can also add community plugins, configurations, and parsers to extend the functionality of ESLint” . The shareable config is the package that bundles those extensions into a single import.


a. The naming convention and the package structure

The ESLint documentation recommends two naming conventions for a shareable config. A standalone package begins with eslint-config-, such as eslint-config-myconfig. A scoped package uses the @scope/eslint-config prefix, such as @scope/eslint-config or @scope/eslint-config-myconfig .

The package exports the config from its main entry point, which is index.js by default. The export can be a single config object or an array of config objects. The documentation recommends an array for most cases, but notes that a single object is also valid .

// index.js
export default [
  {
    rules: {
      semi: [2, "always"],
    },
  },
];

The package.json declares the ESLint dependency in peerDependencies. The recommended form is a >= range with the lowest supported version, such as "eslint": ">= 9" . The peer dependency means the project installs ESLint, and the shareable config uses whatever version the project provides. A config that depends on a plugin or a custom parser declares those packages in dependencies, because they are implementation details of the config, not choices for the project .

The keywords field should include eslint and eslintconfig so that the package is discoverable in the npm search .


b. The extends mechanism in the flat config

The flat config uses the extends key inside a configuration object. The key accepts a config object, a config array, or a string that references a named config from a plugin. The defineConfig helper flattens the extended configs into the array .

// eslint.config.js
import { defineConfig } from "eslint/config";
import myconfig from "eslint-config-myconfig";

export default defineConfig([
  {
    files: ["**/*.js"],
    extends: [myconfig],
    rules: {
      "no-unused-vars": "warn",
    },
  },
]);

The files key scopes the extended config to the matching files. The extends array applies the imported config first, and the rules object after it overrides the specific rules that the project wants to change . The override order is the array order: later objects take precedence over earlier ones for the files they match.

The documentation notes a limitation: “It’s not possible to use shareable configs with the ESLint CLI --config flag” . The --config flag is for a local configuration file, not for a shareable package.


c. The community rule sets

The most widely used shareable configs fall into three categories: style guides, framework-specific configs, and the TypeScript-ESLint tiers.

Airbnb is the strictest and most comprehensive. It enforces semicolons, single quotes, and a large set of React best practices. It requires several peer dependencies, including eslint-plugin-react, eslint-plugin-import, and eslint-plugin-jsx-a11y . The TypeScript variant is eslint-config-airbnb-typescript, which adds the TypeScript parser and the type-aware rules .

Standard is the minimalist option. It has no semicolons, enforces single quotes, and focuses on JavaScript correctness rather than React-specific patterns. Its peer dependencies are eslint-plugin-import, eslint-plugin-n, and eslint-plugin-promise .

Google focuses on readability and clarity for large codebases. It has fewer dependencies than Airbnb and does not include React-specific rules .

TypeScript-ESLint provides a tiered set of configs. The recommended config is the base, the recommended-type-checked config adds rules that require type information, the strict config adds more opinionated rules, and the stylistic config adds rules about code patterns that do not affect program logic . The recommended config also disables core ESLint rules that conflict with the TypeScript rules .

The choice between these configs is a decision about strictness and framework. A React project that wants a comprehensive rule set starts with Airbnb. A Node.js project that wants minimal rules starts with Standard. A TypeScript project starts with the TypeScript-ESLint recommended config and adds stylistic if the team wants the additional pattern rules.


Complete Example Session

// ============================================
// PART 1: THE SHAREABLE CONFIG PACKAGE
// ============================================
// index.js
export default [
  {
    rules: {
      semi: [2, "always"],
      quotes: [2, "single"],
    },
  },
];
// ============================================
// PART 2: THE PACKAGE.JSON
// ============================================
{
  "name": "eslint-config-myconfig",
  "main": "index.js",
  "peerDependencies": {
    "eslint": ">= 9"
  },
  "keywords": ["eslint", "eslintconfig"]
}
// ============================================
// PART 3: THE PROJECT CONFIG
// ============================================
// eslint.config.js
import { defineConfig } from "eslint/config";
import myconfig from "eslint-config-myconfig";

export default defineConfig([
  {
    files: ["**/*.js"],
    extends: [myconfig],
  },
]);
// ============================================
// PART 4: THE OVERRIDE
// ============================================
import { defineConfig } from "eslint/config";
import myconfig from "eslint-config-myconfig";

export default defineConfig([
  {
    files: ["**/*.js"],
    extends: [myconfig],
    rules: {
      "no-unused-vars": "warn",
    },
  },
]);
# ============================================
# PART 5: THE AIRBNB INSTALL
# ============================================
npm install --save-dev eslint-config-airbnb eslint-plugin-react eslint-plugin-import eslint-plugin-jsx-a11y
# ============================================
# PART 6: THE STANDARD INSTALL
# ============================================
npm install --save-dev eslint-config-standard eslint-plugin-import eslint-plugin-n eslint-plugin-promise
// ============================================
// PART 7: THE TYPESCRIPT-ESLINT CONFIG
// ============================================
import tseslint from "typescript-eslint";

export default defineConfig([
  {
    files: ["**/*.ts"],
    extends: [tseslint.configs.recommended],
  },
]);
// ============================================
// PART 8: THE STRICT TIER
// ============================================
import tseslint from "typescript-eslint";

export default defineConfig([
  {
    files: ["**/*.ts"],
    extends: [tseslint.configs.strict],
  },
]);
// ============================================
// PART 9: THE TYPE-CHECKED TIER
// ============================================
import tseslint from "typescript-eslint";

export default defineConfig([
  {
    files: ["**/*.ts"],
    extends: [tseslint.configs.recommendedTypeChecked],
  },
]);
// ============================================
// PART 10: THE DECISION
// ============================================
// React + strict → airbnb
// Minimal Node → standard
// TypeScript → typescript-eslint recommended + stylistic

The ten parts covered the shareable config package, the package.json, the project config, the override, the Airbnb install, the Standard install, the TypeScript-ESLint config, the strict tier, the type-checked tier, and the decision.


Quick Reference

Shareable config package

ItemValue
Naming conventioneslint-config-<name> or @scope/eslint-config
Entry pointindex.js
ExportConfig object or array
ESLint dependencypeerDependencies with >=
Plugin dependenciesdependencies
Keywordseslint, eslintconfig

The extends mechanism

LocationSyntax
Flat configextends: [config] inside an object
Scoped to filesfiles key on the same object
Overriderules after extends
CLI --configNot supported for shareable configs

Community configs

ConfigStylePeer dependencies
AirbnbStrict, semicolons, Reacteslint-plugin-react, import, jsx-a11y
StandardNo semicolons, minimalisteslint-plugin-import, n, promise
GoogleReadability-focusedFew
TypeScript-ESLintTiered (recommended, strict, stylistic)typescript-eslint

TypeScript-ESLint tiers

ConfigIncludes
recommendedCorrectness rules, disables conflicting core rules
recommendedTypeCheckedRecommended + type-aware rules
strictRecommended + more opinionated rules
stylisticPattern rules, no logic impact

Best Practices

✅ Do This:

// Use extends inside a scoped object
{ files: ["**/*.js"], extends: [myconfig] }                  // ✅
// Declare ESLint as a peer dependency
{ "peerDependencies": { "eslint": ">= 9" } }                 // ✅
# Install the peer dependencies the config requires
npm install --save-dev eslint-config-airbnb eslint-plugin-react // ✅
// Override the specific rules the team disagrees with
{ extends: [myconfig], rules: { "no-console": "off" } }      // ✅

❌ Don’t Do This:

// Import the config but do not apply it
import myconfig from "eslint-config-myconfig"                // ❌ (not extended)
# Use the CLI --config flag for a shareable config
eslint --config eslint-config-myconfig                       // ❌
// Put the plugins in peerDependencies when the config requires them
{ "peerDependencies": { "eslint-plugin-react": "*" } }       // ❌

Common Pitfalls

PitfallWhy It HappensFix
Config does not applyImported but not extendedAdd extends: [config]
Plugin not foundPeer dependency not installedInstall the plugin
ESLint version mismatchThe config’s peer dependency is narrowerCheck the config’s peerDependencies
Overrides not appliedThe override object comes before the extendsPut the override after the extends
CLI --config failsShareable configs are not supported by the flagUse the flat config file

Real-World Examples

1. The package export

export default [{ rules: { semi: [2, "always"] } }]

2. The peer dependency

{ "peerDependencies": { "eslint": ">= 9" } }

3. The extends

{ files: ["**/*.js"], extends: [myconfig] }

4. The override

{ extends: [myconfig], rules: { "no-console": "off" } }

5. Airbnb install

npm install --save-dev eslint-config-airbnb eslint-plugin-react

6. Standard install

npm install --save-dev eslint-config-standard eslint-plugin-import

7. TypeScript-ESLint recommended

extends: [tseslint.configs.recommended]

8. TypeScript-ESLint strict

extends: [tseslint.configs.strict]

9. Type-checked tier

extends: [tseslint.configs.recommendedTypeChecked]

10. The decision

React strict → airbnb; minimal → standard; TypeScript → tseslint

Visual

The shareable config package

┌─────────────────────────────────────────────────────────────┐
│  eslint-config-myconfig                                      │
│    ├── index.js        ← exports the config                 │
│    ├── package.json    ← peerDependencies: eslint            │
│    └── dependencies    ← plugins the config needs            │
└─────────────────────────────────────────────────────────────┘

The extends flow

┌─────────────────────────────────────────────────────────────┐
│  eslint.config.js                                            │
│    import myconfig from "eslint-config-myconfig"             │
│       │                                                      │
│       ▼                                                      │
│  { files: ["**/*.js"], extends: [myconfig] }                │
│       │                                                      │
│       ▼                                                      │
│  The config's rules are applied to matching files.           │
│  The project's rules override after the extends.             │
└─────────────────────────────────────────────────────────────┘

The community configs

┌─────────────────────────────────────────────────────────────┐
│  Airbnb      → strict, semicolons, React                    │
│  Standard    → no semicolons, minimalist                    │
│  Google      → readability, large codebases                 │
│  tseslint    → recommended → strict → stylistic             │
└─────────────────────────────────────────────────────────────┘

The TypeScript-ESLint tiers

┌─────────────────────────────────────────────────────────────┐
│  recommended                                                 │
│    └── recommendedTypeChecked (adds type-aware rules)        │
│          └── strict (adds opinionated rules)                 │
│                └── strictTypeChecked (adds type-aware strict)│
│                                                              │
│  stylistic (adds pattern rules, independent of the tiers)    │
└─────────────────────────────────────────────────────────────┘

Summary

ItemValue
Shareable confignpm package exporting a config object or array
Namingeslint-config-<name> or @scope/eslint-config
ESLint dependencypeerDependencies with >=
Plugin dependencydependencies
Applicationextends: [config] in the flat config
CLI --configNot supported for shareable configs
AirbnbStrict, React, many peer dependencies
StandardMinimalist, no semicolons
TypeScript-ESLintTiered: recommended, strict, stylistic

Key takeaways:

  • A shareable config is an npm package that exports a config object or array. The naming convention (eslint-config- or @scope/eslint-config) makes it discoverable, but the export is what matters. The package is imported in eslint.config.js and applied with the extends key .
  • The peer dependency declares the ESLint version. The config does not bundle ESLint; it expects the project to provide it. The >= range in peerDependencies is the supported version contract. The plugins and parsers that the config needs are in dependencies, because they are implementation details .
  • The community rule sets are a decision about strictness and framework. Airbnb is the strictest and the most React-oriented. Standard is the minimalist JavaScript option. Google is the readability-focused option. The TypeScript-ESLint tiers are the base for any TypeScript project, with recommended as the starting point and strict and stylistic as the additional layers .
  • The override is the escape hatch. A project that extends a config and disagrees with a specific rule adds the rule to the rules object after the extends. The override order is the array order, and the project’s rule wins for the files it matches .
  • The CLI --config flag does not work with shareable configs. The flag is for a local configuration file. The shareable config is applied through the extends key in the flat config file .

Remember: A shareable config is a community’s answer to the style debate. Extending one replaces the debate with a dependency, and the dependency comes with a maintenance contract: the config’s authors update it, the project bumps the version, and the rules evolve. The naming convention makes it discoverable, the peer dependency declares the ESLint version, and the extends key applies it. The override is the project’s way to disagree with a specific rule without abandoning the config. And the CLI --config flag is the one place where a shareable config does not work.

Was this helpful?


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!