rushelex/rollup-plugin-circular-dependencies(opens in a new tab)
Language: TypeScript
Detect circular dependencies in Rollup projects
- stars
- 3
- watchers
- 1
- forks
- 1
- open issues
- 0
- Last updated
- 10/07/2026
Language: TypeScript
Detect circular dependencies in Rollup projects
Detect and report circular dependencies in your Rollup & Vite projects.
Circular dependencies cause subtle bugs — from undefined imports at runtime to broken hot module replacement. rollup-plugin-circular-dependencies catches every cycle before your code ships. It plugs into the Rollup/Vite build pipeline, analyses the full module graph with Tarjan's algorithm, and gives you flexible output, lifecycle hooks, and granular filtering.
onStart, onDetected, onEnd callbacks with full Rollup context# Install
npm install -D rollup-plugin-circular-dependencies// rollup.config.js import { circularDependencies } from 'rollup-plugin-circular-dependencies'; export default { input: 'src/index.js', output: { dir: 'dist', format: 'esm' }, plugins: [circularDependencies()], };
That's it. If circular dependencies exist, the build will error by default. Set throwOnError: false to emit warnings instead.
| Requirement | Version |
|---|---|
| Node.js | >=20.12.0 |
| Rollup | ^3.0.0 || ^4.0.0 |
# npm npm install -D rollup-plugin-circular-dependencies # pnpm pnpm add -D rollup-plugin-circular-dependencies # yarn yarn add -D rollup-plugin-circular-dependencies
All options are optional. See the full API reference for details.
import { circularDependencies, DefaultFormatters } from 'rollup-plugin-circular-dependencies'; circularDependencies({ // Enable or disable the plugin enabled: true, // File inclusion pattern (glob or RegExp) include: [/\.(c|m)?[jt]s(x)?$/], // File exclusion pattern (always includes node_modules and .git) exclude: [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/], // Throw a build error on detected cycles (false = warning only) throwOnError: true, // Write output to a file instead of the console outputFilePath: '', // Enable verbose debug logging debug: false, // Transform module paths in the output formatOutModulePath: (p) => p, // Customize output format formatOut: DefaultFormatters.Pretty({ colors: true }), // Selectively ignore specific cycles ignoreCycle: (paths) => paths.some((p) => p.includes('generated')), // Lifecycle callbacks onStart: (pluginContext) => {}, onDetected: (modulePath, pluginContext) => {}, onEnd: ({ rawOutput, formattedOutput, metrics }, pluginContext) => {}, });
// rollup.config.js import { circularDependencies } from 'rollup-plugin-circular-dependencies'; export default { input: 'src/index.js', output: { dir: 'dist', format: 'esm' }, plugins: [ circularDependencies({ throwOnError: false, }), ], };
// vite.config.ts import { defineConfig } from 'vite'; import { circularDependencies } from 'rollup-plugin-circular-dependencies'; export default defineConfig({ plugins: [ circularDependencies({ throwOnError: false, }), ], });
Write detection results to a file (useful for CI pipelines):
circularDependencies({ outputFilePath: './reports/circular-deps.json', throwOnError: false, });
When outputFilePath is set, the default formatter switches to DefaultFormatters.JSON() automatically.
Use the built-in formatters or provide your own:
import circularDependencies, { DefaultFormatters } from 'rollup-plugin-circular-dependencies'; // JSON output to console circularDependencies({ formatOut: DefaultFormatters.JSON(), }); // Pretty output without colors circularDependencies({ formatOut: DefaultFormatters.Pretty({ colors: false }), }); // Fully custom formatter circularDependencies({ formatOut: (data) => { const count = Object.values(data).flat().length; return `Total cycles: ${count}`; }, });
React to detection events with lifecycle callbacks:
circularDependencies({ onStart: (pluginContext) => { console.log('Scanning for circular dependencies...'); }, onDetected: (modulePath, pluginContext) => { console.log(`Cycle member: ${modulePath}`); }, onEnd: ({ rawOutput, formattedOutput, metrics }, pluginContext) => { console.log(`Checked ${metrics.modulesChecked} modules`); console.log(`Found ${metrics.cyclesFound} cycle(s)`); console.log(`Largest cycle: ${metrics.largestCycleSize} modules`); console.log(`Detection took ${metrics.detectionTimeMs.toFixed(1)}ms`); }, });
Filter out known or acceptable cycles:
circularDependencies({ ignoreCycle: (cyclePaths) => { // Ignore cycles involving generated files return cyclePaths.some((p) => p.includes('/generated/')); }, });
rollup-plugin-circular-dependencies — Full API reference, configuration options, and advanced usageSee CHANGELOG.md for a detailed history of changes.
This project is licensed under the MIT License.
If this plugin helps you, consider giving it a ⭐ on GitHub!