oxc-project/oxc · warning · OxcDiagnostic
Barrel file detected, {total} modules are loaded which excee
Error message
Barrel file detected, {total} modules are loaded which exceeds the threshold of {threshold}. What it means
Oxlint rule `oxc/no_barrel_file` uses the module graph to count how many modules a file pulls in via `export *` / `import *` re-exports. When that count exceeds the configured threshold, the file is flagged as a barrel: importing anything from it forces runtimes and bundlers to load and parse the entire re-exported subtree, slowing cold starts and builds.
Source
Thrown at crates/oxc_linter/src/rules/oxc/no_barrel_file.rs:14
use crate::{
ModuleRecord,
context::LintContext,
module_graph_visitor::{ModuleGraphVisitorBuilder, VisitFoldWhile},
rule::{DefaultRuleConfig, Rule},
};
use oxc_diagnostics::{LabeledSpan, OxcDiagnostic};
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use schemars::JsonSchema;
use serde::Deserialize;
fn no_barrel_file(total: u32, threshold: u32, labels: Vec<LabeledSpan>) -> OxcDiagnostic {
OxcDiagnostic::warn(format!(
"Barrel file detected, {total} modules are loaded which exceeds the threshold of {threshold}.",
))
.with_help(format!("Consider importing directly from the specific modules instead of using `export *` or `import *`.\nLoading {total} modules may be slow for runtimes and bundlers."))
.with_note("See: https://marvinh.dev/blog/speeding-up-javascript-ecosystem-part-7")
.with_labels(labels)
}
#[derive(Debug, Clone, JsonSchema, Deserialize)]
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
pub struct NoBarrelFile {
/// The maximum number of modules that can be re-exported via `export *`
/// before the rule is triggered.
threshold: u32,
}
impl Default for NoBarrelFile {
fn default() -> Self {
Self { threshold: 100 }View on GitHub (pinned to e1e7af627c)
Solutions
- Import directly from the specific feature modules at call sites instead of the barrel
- Replace `export *` with explicit named re-exports limited to the public API surface
- Raise the threshold in `.oxlintrc.json` for known-good barrels, or disable the rule via `overrides` for that one file
- Split the barrel into smaller topical entry points
Example fix
// before (src/index.ts)
export * from './button';
export * from './input';
// ... 120 more modules
// after (call sites import directly)
import { Button } from './ui/button';
import { Input } from './ui/input'; Defensive patterns
Strategy: fallback
Validate before calling
// quick pre-check before adding a new export * to a barrel count=$(rg -c "^export \*" src/index.ts || echo 0) echo "barrel re-exports: $count"
Prevention
- Default to importing from feature modules; treat barrels as public API entry points only
- Prefer explicit named re-exports over export * so the reachable module set stays small and greppable
- Watch bundler dev-server cold-start times; a jump usually means a barrel crossed the threshold
When it happens
Trigger: An `index.ts`/`index.js` containing many `export * from './x'` statements (or `import * as ns from './x'; export { ns }` equivalents) whose transitively reachable module count, resolved through the module graph, is greater than the rule's `maximumModules`-style threshold option.
Common situations: Component/utility libraries exporting everything from one index; monorepo package barrels that transitively re-export hundreds of modules; slow dev-server or CI cold starts traced to barrel imports.
Related errors
- Unexpected `await` inside a loop.
- Multiple exports of name '{name}'.
- Dependency cycle detected
- Expected a literal string or immutable template literal
- Unexpected sync method: '{property_name}'.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/78c16ad3863a6b29.
Report an issue: GitHub.