eslint-plugin-no-barrel-files
v2.2.0
Published
ESLint plugin for reducing barrel-file usage in two ways:
Downloads
1,621,297
Maintainers
Readme
eslint-plugin-no-barrel-files
ESLint plugin for reducing barrel-file usage in two ways:
no-barrel-files: disallow authoring barrel filesprefer-source-imports: prefer importing from source modules instead of through a barrel
The plugin is useful both for strict greenfield setups and for incremental migrations away from existing barrels.
Why?
Barrel files can:
- slow down builds and tests
- make circular dependencies easier to introduce
- make tree shaking less effective
- blur module boundaries and make import paths less explicit
References:
- https://github.com/jestjs/jest/issues/11234
- https://github.com/vercel/next.js/issues/12557
- https://dev.to/tassiofront/barrel-files-and-why-you-should-stop-using-them-now-bc4
- https://flaming.codes/posts/barrel-files-in-javascript
Install
npm install --save-dev eslint-plugin-no-barrel-filesprefer-source-imports needs typescript in the consuming project whenever tsconfig resolution is enabled (the default), including when linting JavaScript files. Set tsconfig: false to use only relative imports and the rule's manual paths option instead.
npm install --save-dev typescriptQuick Start
This plugin supports:
- ESLint 9+ and 10+ via flat config
- ESLint 8 via legacy config
Flat Config
import noBarrelFiles from 'eslint-plugin-no-barrel-files';
export default [...noBarrelFiles.configs['flat/recommended']];Legacy Config
module.exports = {
extends: ['plugin:no-barrel-files/recommended'],
};Included Configs
The plugin exports two recommended configs:
configs.recommendedfor legacy configconfigs["flat/recommended"]for flat config
Both enable no-barrel-files and prefer-source-imports.
Rules
no-barrel-files
Disallows common barrel-file patterns such as re-exporting imported bindings or using export *.
// fail
export * from "./foo";
import Foo from "./foo";
export default Foo;
import Foo from "./foo";
export { Foo };
export { Moo } from "./Moo";
export { default as Moo } from "./Moo";
// pass
const Foo = "baz";
function Bar() {}
class Baz {}
export default Foo;
export { Bar, Baz };
import { Moo } from "./Moo";
export const Baz = Moo;Use this rule when you want to stop new barrel files from being created.
Options
allow
Allows intentional barrel files whose path matches one of the supplied glob patterns. Patterns match paths relative to the current working directory; absolute patterns are also supported.
{
'no-barrel-files/no-barrel-files': ['error', {
allow: ['src/index.ts', 'packages/*/src/index.ts'],
}],
}prefer-source-imports
Reports imports that go through a barrel when the rule can resolve the original source module.
// fail
import { Foo } from './barrel';
import type { TypeFoo } from './barrel';
// if barrel.ts contains:
// export { Foo } from "./foo";
// export type { TypeFoo } from "./types";
// pass
import { Foo } from './foo';
import type { TypeFoo } from './types';This rule is useful when:
- a codebase still has barrel files
- you want to migrate consumers away from barrels gradually
- you want autofixable guidance where possible
What it can resolve
prefer-source-imports currently supports:
- relative imports
- TypeScript
baseUrlandpathsfrom the nearesttsconfig.json - explicit alias mappings through the
pathsrule option - explicit re-exports such as
export { Foo } from "./foo" - aliased re-exports such as
export { Bar as Foo } from "./bar" - local re-exports such as
import { Foo } from "./foo"; export { Foo } - default re-exports such as
export { default as Foo } from "./foo" export * from "./foo"when the exported name can be resolved back to the source file- type-only re-exports such as
export type { Foo } ...andexport { type Foo } ...
Current scope:
- the rule focuses on named imports
- default imports are rewritten when the barrel directly re-exports its default export
- namespace imports are not the target of this rule
Safe autofix behavior
The rule only autofixes when the full import declaration can be rewritten safely.
If only part of an import can be resolved safely, the rule still reports the problem but may skip autofix.
prefer-source-imports Options
fixStyle
Controls how the replacement import path is generated.
"relative"Always rewrites to a relative import path."preserve-alias"Preserves an alias only when the reverse alias mapping is unique."auto"Preserves aliases for alias-based imports when the reverse alias mapping is unique; otherwise falls back to a relative path.
ignore
Skips imports whose source specifier matches one of the supplied glob patterns. Use this for intentional public barrel APIs while continuing to fix internal barrel imports.
import noBarrelFiles from 'eslint-plugin-no-barrel-files';
export default [
{
plugins: {
'no-barrel-files': noBarrelFiles,
},
rules: {
'no-barrel-files/prefer-source-imports': ['error', {
ignore: ['@acme/ui', '@acme/*/public'],
}],
},
},
];tsconfig
Controls tsconfig-based path resolution.
- omitted or
trueUse the nearesttsconfig.json. falseDisable tsconfig-based resolution entirely."./path/to/tsconfig.json"Resolve using a specific config file.
paths
Manual alias mappings that supplement or replace tsconfig path resolution.
Values can be:
- a string
- an array of strings
Example:
{
paths: {
"@app/*": "src/*",
"@shared/*": ["packages/shared/src/*", "src/shared/*"],
},
}Configuration Examples
Enable Only no-barrel-files
This blocks new barrel files, but does not yet enforce direct source imports.
import noBarrelFiles from 'eslint-plugin-no-barrel-files';
export default [
{
plugins: {
'no-barrel-files': noBarrelFiles,
},
rules: {
'no-barrel-files/no-barrel-files': 'error',
},
},
];Enable Both Rules
This is a good migration setup.
import noBarrelFiles from 'eslint-plugin-no-barrel-files';
export default [...noBarrelFiles.configs['flat/recommended']];Use Manual Alias Resolution Only
import noBarrelFiles from 'eslint-plugin-no-barrel-files';
export default [
{
plugins: {
'no-barrel-files': noBarrelFiles,
},
rules: {
'no-barrel-files/prefer-source-imports': [
'error',
{
tsconfig: false,
fixStyle: 'preserve-alias',
paths: {
'@app/*': 'src/*',
},
},
],
},
},
];Use A Specific tsconfig.json
import noBarrelFiles from 'eslint-plugin-no-barrel-files';
export default [
{
plugins: {
'no-barrel-files': noBarrelFiles,
},
rules: {
'no-barrel-files/prefer-source-imports': [
'error',
{
tsconfig: './tsconfig.eslint.json',
fixStyle: 'auto',
},
],
},
},
];Adoption Strategy
Typical rollout options:
- Start with
no-barrel-filesonly to block new barrels. - Add
prefer-source-importslater to migrate consumers away from old barrels. - Run
prefer-source-importsfirst if the codebase already has many barrels and you want to shrink their usage before deleting them.
Notes
prefer-source-importsdepends on being able to resolve the barrel and the underlying source module.prefer-source-importsuses the consuming project'stypescriptinstallation for tsconfig parsing and module resolution.- The current TypeScript peer-dependency range is
^5.6.3 || ^6.0.0. TypeScript 7 is not supported yet. - If
prefer-source-importsruns on a TypeScript file withouttypescriptinstalled and tsconfig resolution is enabled, the rule reports a configuration error instead of crashing the plugin. - The same configuration error is reported for JavaScript files when the rule needs tsconfig-based resolution but
typescriptis not installed. - Alias preservation only happens when reverse alias lookup is unique.
- If multiple aliases point to the same file, the fixer may fall back to a relative path or skip autofix depending on
fixStyle.
Contributing
If you find a bug or want an additional feature, open an issue or send a pull request.
