Skip to main content

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

1

Create npm Package

Initialize a new package:
mkdir eslint-config-myconfig
cd eslint-config-myconfig
npm init -y
2

Create Configuration File

Create index.js as the entry point:
index.js
export default [
  {
    languageOptions: {
      globals: {
        MyGlobal: true
      }
    },
    
    rules: {
      semi: ["error", "always"],
      quotes: ["error", "double"],
      "no-unused-vars": "error"
    }
  }
];
3

Configure package.json

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"
  }
}
4

Publish

npm publish

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:
index.js
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:
index.js
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:
npm install --save-dev eslint-config-myconfig

Extending Configurations

Build on top of other configs:
index.js
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:
eslint.config.js
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:
export default [
  {
    rules: {
      semi: ["error", "always"],
      quotes: ["error", "double"]
    }
  }
];
Users can import specific configs:
eslint.config.js
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:
index.js
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:
eslint.config.js
import createConfig from "eslint-config-myconfig";

export default createConfig({
  strict: true,
  react: true
});

Including Plugins

Bundle plugins with your config:
index.js
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:
index.js
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:
index.js
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:
index.js
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:
test/config.test.js
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:
README.md
# 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

1

Package Configuration

  • Correct main entry point
  • Appropriate keywords in package.json
  • peerDependencies for ESLint
  • dependencies for included plugins
2

Documentation

  • Comprehensive README
  • Installation instructions
  • Usage examples
  • Rule documentation
  • Migration guide (if updating)
3

Testing

  • Test config with ESLint
  • Verify all plugins work
  • Test overrides
  • Check edge cases
4

Versioning

  • Follow semantic versioning
  • Maintain changelog
  • Document breaking changes

Maintenance

Version Updates

Update peer dependencies:
package.json
{
  "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:
  1. Keep configs focused - One concern per config
  2. Document thoroughly - Examples for every rule
  3. Test configurations - Verify with real code
  4. Version carefully - Breaking changes need major version bump
  5. Stay updated - Keep plugin dependencies current
  6. 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:
index.js
// 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