A globally shareable ESLint config for Octopus Energy repositories.
A publicly available ESLint config by Octopus Energy Group.
---
This package provides a wide range of "recommended" ESLint configs with the goal of minimising end-user configuration and increasing consistency across projects. It is designed around ESLint v9 to allow for easily shareable, modular and extensible configurations by leveraging the new "Flat" config files.
We publish our ESLint config publicy on npm. No registry token or
authentication is required to install the config. Install it alongside the latest eslint version using your preferred
package manager:
``sh`
pnpm add -D @krakentech/eslint-config eslint
`sh`
yarn add -D @krakentech/eslint-config eslint
`sh`
npm install --save-dev @krakentech/eslint-config eslint
> [!NOTE]
> If you are using a monorepo it's still recommended to install the package at the root of the project. ESlint v9 is now able to apply rules _top down_, making it trivial to limit specific rule-sets to the right files. For example, the recommended NextJS package can easily be restricted to apps/web if that is the only NextJS application in the monorepo.
Do I need a shared package in a monorepo?
Probably not! Because of how ESLint v9 and the new "Flat" configs work, this package is able to define all of the different plugins as dependencies. So, rather than having to create a shared eslint config we can easily just install this package at the root to share it across the whole repo.
If you would prefer to use a shared package or per-package config files then you can too. Install this package into the shared package and distribute accordingly. This package does not mind how you want to setup your repo.
ESLint v9 now enforces the use of a file named eslint.config.js. This should be placed at the root of your project. Configuration of the whole repository can be done from this single file. Simply load the package and export linters.load(FlatConfig, ...).
Each FlatConfig only requires the user to define which files should have which plugins applied to them (or ignores) and which plugins the config extends from. You can pass as many configs as you like.
> [!IMPORTANT]
> If you don't define any files for a config, the default behaviour it to lint all project files! This may affect performance.
| Single Package Example | Monorepo Example |
|---|---|
` const linters = require("@krakentech/eslint-config"); module.exports = linters.load( |
const linters = require("@krakentech/eslint-config"); module.exports = linters.load( |
> [!TIP]
> We support both CJS and ESM config files! You can use import and export default if your package package type is set to module.
Whilst we suggest that you try to use the recommended configurations where possible to maintain consistency across projects, it is still simple to "extend" our recommended configs and "override" specific rules.
#### Simple Typescript Package
For example, lets say we want to create a ReactJS project that uses Typescript and disables the @typescript-eslint/no-explicit-any rule:
`ts
// eslint.config.js
const linters = require("@krakentech/eslint-config");
module.exports = linters.load(
// ... other configs
{
files: ["*/.{ts,tsx}"],
extends: [
// Load recommended Javascript rules
...linters.configs.javascript.recommended,
// Load the recommended typescript configs
...linters.configs.typescript.recommended,
// Then extend it with the React config
...linters.configs.react.recommended,
],
// Override a specific rule
rules: {
"@typescript-eslint/no-explicit-any": "off",
},
},
);
`
#### Monorepo with multiple apps, packages and tests
`ts
// eslint.config.js
const linters = require("@krakentech/eslint-config");
module.exports = linters.load(
// Global ignores across the whole repo
{
ignores: ["/node_modules/", "/build/", "/.typegen./"],
},
// Apply Javascript recommended rules to all js(x) and ts(x) files
{
files: ["*/.{js,jsx,ts,tsx}"],
extends: linters.configs.javascript.recommended,
},
// Apply next recommended rules to all apps
{
files: ["apps/*/.{ts,tsx}"],
extends: linters.configs.next.recommended,
},
// Only apply typescript rules to packages
{
files: ["packages/*/.{ts,mts,cts}"],
extends: linters.configs.typescript.recommended,
},
// Applies react rules to all react files. This should also catch most test
// files too.
{
files: ["*/.{jsx,tsx}"],
extends: [
...linters.configs.react.recommended, // Includes jsxa11y
],
},
// Applies jest rules to test files
{
files: ["*/.spec.{js,jsx,ts,tsx}"],
extends: linters.configs.jest.recommended,
},
);
`
> [!TIP]
> Some plugins have "utility" configs that do something specific to that plugin (_usually_ to disable rules). Use these the same way you would use the base configs.
Why do we use
extends
The load utility automatically merges configs inside of the extends field into a single config. This means we don't have to do fiddly spreading of multiple base configs.
Package Interface
`ts
export type LinterConfig = {
base: FlatConfig;
recommended: ConfigArray;
utils?: Record
};
export type PackageConfig = {
load: (...configs: InfiniteDepthConfigWithExtends[]) => ConfigArray;
configs: Record
};
`
For each plugin, we expose a base and recommended config.
- Base configs contain setup and rules for the specific ESLint plugin.
- Recommended configs are what we recommend when using that plugin in your project. _Recommended configs may contain multiple different configs to reflect their dependencies (e.g. NextJS requiring React)_.
Most recommended configs contain only the base plugin because they are use usually used in isolation. However, the Typescript, React and NextJS plugins contain the following plugins:
| Plugin | Typescript | React | NextJS |
| ---------------------------------: | :--------: | :---: | :----: |
| @eslint/js | ✅ | ⛔ | ✅ |typescript-eslint
| | ✅ | ⛔ | ✅ |eslint-plugin-import
| | ✅ | ⛔ | ✅ |eslint-plugin-simple-import-sort
| | ✅ | ⛔ | ✅ |eslint-plugin-react
| | ⛔ | ✅ | ✅ |eslint-plugin-react-hooks
| | ⛔ | ✅ | ✅ |eslint-plugin-jsx-a11y
| | ⛔ | ✅ | ✅ |@next/eslint-plugin-next
| | ⛔ | ⛔ | ✅ |eslint-plugin-turbo
| | ⛔ | ⛔ | ⛔ |@vitest/eslint-plugin
| | ⛔ | ⛔ | ⛔ |eslint-plugin-jest
| | ⛔ | ⛔ | ⛔ |eslint-plugin-prettier
| | ⛔ | ⛔ | ⛔ |
> [!IMPORTANT]
> The recommended configs are configurations we think you should use in your projects, _not_ that they necessarily use the recommended rules sets. Whilst most do use the recommended rule sets, it's good to check which rules sets using the JSDoc strings on each export or the plugin details below.
#### Overrides
- no-console - ["error", { allow: ["warn"] }]
---
- Recommended rule set
- Strict TypeChecked rules
We use the "Strict TypeChecked" rules (which automatically brings in the "Recommended" rules) to provide the most accurate type checking.
#### Overrides
- @typescript-eslint/no-unused-vars_
- Allows the use of the prefix for unused variables{ ignoreMe, ...butNotMe } = someObject
- Will ignore unused destructured rest siblings: @typescript-eslint/consistent-type-imports
- type
- Prefers types are always imported using the keywordimport { type Foo }
- e.g. over import { Foo }import/consistent-type-specifier-style
- This works well the fixable rule to ensure import consistency.
The following have been disabled:
- @typescript-eslint/no-confusing-void-expression - Off@typescript-eslint/restrict-template-expressions
- - Off@typescript-eslint/no-unsafe-enum-comparison
- - Off@typescript-eslint/unbound-method
- - Off@typescript-eslint/no-floating-promises
- - Off
> [!TIP]
> We provide the configs.typescript.utils.disableTypeChecking utility to disable the type checking rules if you need to disable type checking for whatever reason (e.g. old JSX only components).
---
We use both packages in configs.imports.recommended. We prefer eslint-plugin-simple-import-sort for import sorting because it requires less configuration to apply sensible sorting, is easier to configure and _only creates an single issue if there's an error in the sorting_. We also include eslint-plugin-import for a few rules that the former does not handle:
- import/first - Ensure all imports appear before other statements.import/newline-after-import
- - Enforce a newline after import statements.import/no-duplicates
- - Forbid repeated import of the same module in multiple places.import/consistent-type-specifier-style
- - Ensure that we consistently use import { type Foo }.
configs.imports.utils.disableSimpleImportSort
We provide the ability to disable the simple-import-sort plugin if it does not fit well with your project. Simply extend your config with this utility like so:
`ts
// eslint.config.js
import linters from "@krakentech/eslint-config";
export default linters.load({
files: ["*/.{ts,tsx}"],
extends: [
...linters.configs.typescript.recommended,
linters.configs.imports.utils.disableSimpleImportSort,
],
});
`
---
- eslint-plugin-react Recommended Rule Set
- eslint-plugin-jsx-a11y Strict Rule Set
- react-hooks/rules-of-hooks - Enforce rules of hooks.react-hooks/exhaustive-deps
- - Validate hook dependency arrays.react-hooks/react-compiler
- - Raises errors in case of unsafe hooks usage - follows the Rules of React
#### Overrides
- react/prop-types - Off.react/react-in-jsx-scope
- - Off.
---
- Recommended and Core Web Vitals Rule Sets
---
---
---
---
> [!IMPORTANT]
> Prettier is not enabled by default in our recommended configs. The official advice by both the Prettier team _and_ the ESLint team is to not integrate Prettier rules into your ESLint config. Formatters should be something you forget about; lots of red squiggly lines in your editor can be distracting as well as less performant.
However, it is _expected_ that users implement Prettier into their workflow
at some point. Ideally users integrate Prettier into their editors, or you run Prettier as a file watcher.
Alternatively (or in addition to), you can conditionally enable Prettier during CI to ensure committed code is formatted correctly:
`js
// eslint.config.js
// This is the common CI ennvar, however, adjust to your system
const isCI = process.env.CI;
export default linters.load(
...
// Enable Prettier in CI only
isCI && {
// No files array will lint all files
extends: linters.configs.recommended.prettier,
},
...
};
``
> [!NOTE]
> Prettier should be enabled as your last config so that it can override any rules it might conflict with.
This table details which rules have been added or removed from the last major release (also compatibility with Biome given it looks like a promising upgrade from ESLint).