Shareable Configurations
Shareable configs allow you to package and distribute ESLint configurations across multiple projects. They’re perfect for enforcing team standards, company-wide rules, or community best practices.
What is a Shareable Config?
A shareable config is an npm package that exports an ESLint configuration object or array. It enables:
Consistent linting across projects
Team coding standards
Framework-specific configurations
Company-wide rule enforcement
Easy configuration updates
Popular Shareable Configs:
@eslint/js - ESLint’s official JavaScript configs
eslint-config-airbnb - Airbnb’s JavaScript style guide
eslint-config-standard - JavaScript Standard Style
eslint-config-prettier - Disable conflicting Prettier rules
Creating a Shareable Config
Create npm Package
Initialize a new package: mkdir eslint-config-myconfig
cd eslint-config-myconfig
npm init -y
Create Configuration File
Create index.js as the entry point: export default [
{
languageOptions: {
globals: {
MyGlobal: true
}
} ,
rules: {
semi: [ "error" , "always" ],
quotes: [ "error" , "double" ],
"no-unused-vars" : "error"
}
}
] ;
Configure package.json
{
"name" : "eslint-config-myconfig" ,
"version" : "1.0.0" ,
"description" : "My shareable ESLint config" ,
"main" : "index.js" ,
"type" : "module" ,
"keywords" : [ "eslint" , "eslintconfig" ],
"peerDependencies" : {
"eslint" : ">= 9"
}
}
Config Naming Conventions
Follow these naming conventions: Unscoped:
Begin with eslint-config-
Example: eslint-config-myconfig
Scoped:
Format: @scope/eslint-config or @scope/eslint-config-name
Examples: @company/eslint-config, @company/eslint-config-react
Basic Config Structure
Export an array of configuration objects:
export default [
{
// Language options
languageOptions: {
ecmaVersion: 2024 ,
sourceType: "module" ,
globals: {
window: "readonly" ,
document: "readonly"
},
parserOptions: {
ecmaFeatures: {
jsx: true
}
}
} ,
// Rules
rules: {
"no-console" : "warn" ,
"no-unused-vars" : [ "error" , {
argsIgnorePattern: "^_"
}],
"prefer-const" : "error" ,
"arrow-body-style" : [ "error" , "as-needed" ]
}
}
] ;
Single Config Object
You can also export a single configuration:
export default {
languageOptions: {
ecmaVersion: 2024
} ,
rules: {
semi: [ "error" , "always" ]
}
} ;
When exporting a single object, make sure your documentation clearly shows how to use it with the extends key in eslint.config.js.
Using a Shareable Config
Install and use the config:
Installation
eslint.config.js
npm install --save-dev eslint-config-myconfig
Extending Configurations
Build on top of other configs:
import js from "@eslint/js" ;
import prettier from "eslint-config-prettier" ;
export default [
// Include base configs
js . configs . recommended ,
prettier ,
// Add custom rules
{
rules: {
"no-console" : "warn" ,
"prefer-const" : "error"
}
}
] ;
Overriding Settings
Users can override your config:
import myconfig from "eslint-config-myconfig" ;
export default [
{
extends: [ myconfig ] ,
// Override rules
rules: {
"no-console" : "off" , // Disable
semi: [ "error" , "never" ] // Change option
}
}
] ;
Multiple Configurations
Export multiple configs from one package:
index.js (Main Export)
strict.js
react.js
export default [
{
rules: {
semi: [ "error" , "always" ],
quotes: [ "error" , "double" ]
}
}
] ;
Users can import specific configs:
import myconfig from "eslint-config-myconfig" ;
import strict from "eslint-config-myconfig/strict.js" ;
import react from "eslint-config-myconfig/react.js" ;
export default [
{
extends: [ myconfig , strict , react ]
}
] ;
Dynamic Configurations
Generate configs programmatically:
export default function createConfig ( options = {}) {
const { strict = false , react = false } = options ;
const config = [
{
rules: {
semi: [ "error" , "always" ],
quotes: [ "error" , "double" ]
}
}
];
if ( strict ) {
config . push ({
rules: {
"no-console" : "error" ,
"no-debugger" : "error"
}
});
}
if ( react ) {
config . push ({
plugins: {
react: require ( "eslint-plugin-react" )
},
rules: {
"react/jsx-uses-react" : "error"
}
});
}
return config ;
}
Usage:
import createConfig from "eslint-config-myconfig" ;
export default createConfig ({
strict: true ,
react: true
}) ;
Including Plugins
Bundle plugins with your config:
import importPlugin from "eslint-plugin-import" ;
import promisePlugin from "eslint-plugin-promise" ;
export default [
{
plugins: {
import: importPlugin ,
promise: promisePlugin
} ,
rules: {
// Plugin rules
"import/no-unresolved" : "error" ,
"import/named" : "error" ,
"promise/always-return" : "error"
}
}
] ;
Dependencies:
Add plugins as dependencies (not peerDependencies) in your package.json:{
"dependencies" : {
"eslint-plugin-import" : "^2.29.0" ,
"eslint-plugin-promise" : "^6.1.0"
},
"peerDependencies" : {
"eslint" : ">= 9"
}
}
Including Parsers
Bundle custom parsers:
import tsParser from "@typescript-eslint/parser" ;
import tsPlugin from "@typescript-eslint/eslint-plugin" ;
export default [
{
files: [ "**/*.ts" , "**/*.tsx" ] ,
languageOptions: {
parser: tsParser ,
parserOptions: {
project: "./tsconfig.json"
}
} ,
plugins: {
"@typescript-eslint" : tsPlugin
} ,
rules: {
"@typescript-eslint/no-unused-vars" : "error" ,
"@typescript-eslint/explicit-function-return-type" : "warn"
}
}
] ;
Real-World Example
Comprehensive config for React projects:
import js from "@eslint/js" ;
import reactPlugin from "eslint-plugin-react" ;
import reactHooksPlugin from "eslint-plugin-react-hooks" ;
import jsxA11yPlugin from "eslint-plugin-jsx-a11y" ;
import importPlugin from "eslint-plugin-import" ;
import prettier from "eslint-config-prettier" ;
export default [
// Base JavaScript config
js . configs . recommended ,
// React-specific config
{
files: [ "**/*.{js,jsx,mjs,cjs,ts,tsx}" ] ,
plugins: {
react: reactPlugin ,
"react-hooks" : reactHooksPlugin ,
"jsx-a11y" : jsxA11yPlugin ,
import: importPlugin
} ,
languageOptions: {
parserOptions: {
ecmaFeatures: {
jsx: true
}
},
globals: {
React: "readonly"
}
} ,
settings: {
react: {
version: "detect"
}
} ,
rules: {
// React rules
"react/jsx-uses-react" : "error" ,
"react/jsx-uses-vars" : "error" ,
"react/react-in-jsx-scope" : "off" ,
"react/prop-types" : "off" ,
// React Hooks rules
"react-hooks/rules-of-hooks" : "error" ,
"react-hooks/exhaustive-deps" : "warn" ,
// Accessibility rules
"jsx-a11y/alt-text" : "warn" ,
"jsx-a11y/anchor-is-valid" : "warn" ,
// Import rules
"import/no-unresolved" : "error" ,
"import/named" : "error" ,
"import/default" : "error" ,
"import/namespace" : "error"
}
},
// Disable conflicting Prettier rules
prettier
] ;
File-Specific Configs
Provide different configs for different file types:
export default [
// Base config for all JavaScript
{
files: [ "**/*.js" ] ,
rules: {
semi: [ "error" , "always" ],
quotes: [ "error" , "double" ]
}
},
// Config for test files
{
files: [ "**/*.test.js" , "**/*.spec.js" ] ,
languageOptions: {
globals: {
describe: "readonly" ,
it: "readonly" ,
expect: "readonly"
}
} ,
rules: {
"no-console" : "off" // Allow console in tests
}
},
// Config for Node.js scripts
{
files: [ "scripts/**/*.js" ] ,
languageOptions: {
sourceType: "commonjs" ,
globals: {
__dirname: "readonly" ,
__filename: "readonly" ,
require: "readonly" ,
module: "readonly"
}
}
}
] ;
Environment-Specific Configs
Create configs for different environments:
export default [
{
languageOptions: {
globals: {
window: "readonly" ,
document: "readonly" ,
navigator: "readonly" ,
localStorage: "readonly"
}
} ,
rules: {
"no-console" : "warn"
}
}
] ;
Testing Configs
Test your shareable config:
import { ESLint } from "eslint" ;
import config from "../index.js" ;
const eslint = new ESLint ({
overrideConfigFile: true ,
overrideConfig: config
});
// Test valid code
const validResults = await eslint . lintText ( 'const x = 1;' );
console . assert (
validResults [ 0 ]. errorCount === 0 ,
"Should have no errors"
);
// Test invalid code
const invalidResults = await eslint . lintText ( 'var x = 1' );
console . assert (
invalidResults [ 0 ]. errorCount > 0 ,
"Should have errors"
);
console . log ( "All tests passed!" );
Documentation Template
Provide clear documentation:
# eslint-config-myconfig
Shareable ESLint config for MyCompany projects.
## Installation
\`\`\` bash
npm install --save-dev eslint-config-myconfig
\`\`\`
## Usage
Create `eslint.config.js` :
\`\`\` javascript
import myconfig from "eslint-config-myconfig";
export default [
{
files: [ "**/*.js" ],
extends: [ myconfig ]
}
];
\`\`\`
## Configurations
### Default
Standard configuration for all projects.
\`\`\` javascript
import myconfig from "eslint-config-myconfig";
\`\`\`
### Strict
Stricter rules for production code.
\`\`\` javascript
import strict from "eslint-config-myconfig/strict.js";
\`\`\`
### React
Additional rules for React projects.
\`\`\` javascript
import react from "eslint-config-myconfig/react.js";
\`\`\`
## Rules
### Code Quality
- `no-console` : Warn on console statements
- `no-unused-vars` : Error on unused variables
- `prefer-const` : Prefer const over let
### Formatting
- `semi` : Require semicolons
- `quotes` : Use double quotes
- `indent` : 2 spaces
## Extending
Override rules:
\`\`\` javascript
import myconfig from "eslint-config-myconfig";
export default [
{
extends: [ myconfig ],
rules: {
"no-console": "off" // Disable rule
}
}
];
\`\`\`
## License
MIT
Publishing Checklist
Maintenance
Version Updates
Update peer dependencies:
{
"peerDependencies" : {
"eslint" : ">= 9.0.0"
}
}
Deprecation
When deprecating rules:
export default [
{
rules: {
// Deprecated - use 'new-rule' instead
"old-rule" : "off" ,
"new-rule" : "error"
}
}
] ;
Best Practices
Follow these guidelines:
Keep configs focused - One concern per config
Document thoroughly - Examples for every rule
Test configurations - Verify with real code
Version carefully - Breaking changes need major version bump
Stay updated - Keep plugin dependencies current
Provide overrides - Make configs customizable
Config Organization
// Good: Organized by category
export default [
{
rules: {
// Possible Errors
"no-console" : "warn" ,
"no-debugger" : "error" ,
// Best Practices
"prefer-const" : "error" ,
"no-var" : "error" ,
// Style
"semi" : [ "error" , "always" ],
"quotes" : [ "error" , "double" ]
}
}
] ;
Legacy Config Support
Support both flat and legacy formats:
// Flat config (recommended)
export const flatConfig = [
{
rules: {
semi: [ "error" , "always" ]
}
}
];
// Legacy config
export const legacyConfig = {
rules: {
semi: [ "error" , "always" ]
}
};
// Default export for flat config
export default flatConfig ;
Users choose format:
// Flat config
import config from "eslint-config-myconfig" ;
// Legacy config
import { legacyConfig } from "eslint-config-myconfig" ;
Real-World Examples
@eslint/js Official ESLint JavaScript configs
eslint-config-airbnb Airbnb’s style guide
eslint-config-standard JavaScript Standard Style
eslint-config-prettier Disable Prettier conflicts
Next Steps
Create a Plugin Package rules with your config
Custom Rules Add custom rules to your config