Dependency Cruiser
Dependency Cruiser is a static analysis tool for validating and visualizing dependencies in JavaScript, TypeScript, and CoffeeScript projects, supporting various module systems including ES6, CommonJS, and AMD. Currently at version 17.3.10, the project demonstrates an active release cadence with frequent maintenance and feature updates. Key differentiators include its ability to define and enforce custom architectural rules, detect issues like circular dependencies or missing `package.json` entries, and generate highly customizable dependency graphs in multiple formats such as DOT, SVG, Mermaid, JSON, HTML, or plain text. It offers both a command-line interface for quick analysis and reporting, and a programmatic API for deeper integration into build processes or custom tooling.
Common errors
-
Error: Cannot find module 'typescript'
cause Attempting to analyze a TypeScript project without `typescript` installed as a dependency or globally.fixInstall TypeScript: `npm install --save-dev typescript` (local) or `npm install -g typescript` (global). -
Error: Unknown output type 'svg' (or 'png', 'jpg')
cause Using an output type directly (like `svg`) that `dependency-cruiser` doesn't generate natively; these formats require an external tool like `Graphviz`.fixUse `--output-type dot` with `dependency-cruiser` and then pipe the output to the `dot` command from Graphviz: `npx depcruise src --output-type dot | dot -T svg > output.svg`. -
ERROR: [no-circular] (dependency-graph.js) → main.js
cause A circular dependency was detected in your codebase, violating a rule configured in `.dependency-cruiser.js`.fixRefactor your modules to break the circular dependency. This often involves applying dependency inversion principles, extracting shared logic to a common module, or re-evaluating module responsibilities. -
TypeError: (0, dependency_cruiser_1.cruise) is not a function
cause Attempting to use `dependency-cruiser`'s programmatic API with CommonJS `require` syntax or without properly awaiting the `cruise` function after upgrading to v13+.fixFor v13+, the API is ESM-only and asynchronous. Change your import to `import { cruise } from 'dependency-cruiser';` and ensure you `await cruise(...)` within an `async` function.
Warnings
- breaking Starting with v13, the `--config` CLI option is no longer necessary and is ignored if a `.dependency-cruiser.js` file is found in the current directory or a parent. If you explicitly passed `--config` in v12 or older, you can remove it. For programmatic API users, v13 introduced several breaking changes including an ESM-only API, asynchronous `cruise` function, and a changed `cruise` signature.
- gotcha When using `pnpx` (from pnpm) instead of `npx`, be aware that `pnpx` has different semantics which might affect how commands are executed or how packages are resolved. The documentation advises caution when mixing package managers.
- gotcha Generating visual output formats like SVG from the `.dot` format requires the external `Graphviz` tool to be installed on your system. `dependency-cruiser` itself outputs `.dot` files, which then need to be piped to the `dot` command.
- gotcha The `picomatch` library, an internal dependency, had a reported vulnerability that was deemed 'irrelevant for dependency-cruiser's context' in a recent release. However, this might still trigger false positives in automated security scanners.
- gotcha For TypeScript projects, if you observe that dependencies within TypeScript files (especially pre-compilation ones) are not correctly analyzed or found, it might be due to `dependency-cruiser` not finding the TypeScript compiler. It uses the transpiler already in your project or globally.
Install
-
npm install dependency-cruiser -
yarn add dependency-cruiser -
pnpm add dependency-cruiser
Imports
- cruise
const cruise = require('dependency-cruiser');import { cruise } from 'dependency-cruiser'; - format
import format from 'dependency-cruiser/format';
import { format } from 'dependency-cruiser'; - IConfiguration
import { IConfiguration } from 'dependency-cruiser';import type { IConfiguration } from 'dependency-cruiser';
Quickstart
npm install --save-dev dependency-cruiser
npx depcruise --init
# Answer prompts to generate .dependency-cruiser.js configuration
# Run analysis and generate an SVG graph using Graphviz dot tool
npx depcruise src --include-only "^src" --output-type dot | dot -T svg > dependency-graph.svg
# For programmatic use, e.g., in a CI/CD pipeline or custom script:
// my-analysis.ts
import { cruise, format } from 'dependency-cruiser';
import type { IConfiguration, ICruiseResult } from 'dependency-cruiser';
const config: IConfiguration = {
forbidden: [
{
name: 'no-circular',
comment: 'This dependency is part of a circular relationship.',
severity: 'warn',
from: {}, to: { circular: true }
},
{
name: 'no-internal-to-external',
comment: 'Don\'t allow internal code to depend on external libraries outside of an adapter layer.',
severity: 'error',
from: { path: '^src/(?!adapters)' },
to: { dependencyTypes: ['npm', 'npm-dev'] }
}
],
options: {
// Configure to resolve TypeScript paths, etc.
tsPreCompilationDeps: true,
doNotFollow: {
path: 'node_modules'
},
moduleSystems: ['es6', 'cjs'],
}
};
async function analyzeDependencies() {
try {
const { output, exitCode } = await cruise(
['src'], // Files or globs to cruise
config
) as ICruiseResult;
if (exitCode !== 0) {
console.error('Dependency violations found:\n', output);
} else {
console.log('No dependency violations found.');
}
// Example of using format for custom reporting (e.g., HTML)
// const htmlReport = format(output, { outputType: 'html' });
// console.log(htmlReport);
} catch (error: any) {
console.error('Error during dependency cruising:', error.message);
process.exit(1);
}
}
analyzeDependencies();