Local-first dependency analysis tool that generates a single HTML report showing risk, size, usage, and structure of your project's dependencies.
npm install dependency-radarDependency Radar is a CLI tool that inspects a Node.js project’s installed dependencies and generates a single, human-readable HTML report. The report highlights dependency structure, usage, licences, vulnerabilities, and other signals that help you understand risk and complexity hidden in your node_modules folder.
The simplest way to get started is:
``bash`
npx dependency-radar
This runs a scan against the current project and writes a self-contained dependency-radar.html report you can open locally, share with teammates, or attach to tickets and documentation.
- Analyses installed dependencies by running standard package manager tooling (npm, pnpm, or yarn)
- Combines multiple signals (audit results, dependency graph data, import usage, and heuristics) into a single report
- Shows direct vs transitive dependencies, dependency depth, and parent relationships
- Highlights licences, known vulnerabilities, install-time scripts, native modules, and package footprint
- Produces a single self-contained HTML file with no external assets, which you can easily share
- Not a CI service or hosted scanning platform
- Not a replacement for dedicated security scanners
- Not a bundler or build tool
- Not a dependency updater
---
For teams that want deeper analysis, long-term tracking, and additional enrichment (such as ecosystem and maintenance signals), Dependency Radar also offers an optional premium service.
See https://dependency-radar.com for details.
Dependency Radar validates SPDX licenses declared in package.json and can infer licenses from LICENSE files when declarations are missing or invalid. It works offline and uses a bundled SPDX identifier list (generated at build time) with no runtime network access. Each dependency gets a structured license record with:
- Declared SPDX validation (including deprecated IDs and WITH exceptions)high
- Inferred SPDX license (with confidence: , medium, low) based on deterministic text matchingdeclared-only
- A status (, inferred-only, match, mismatch, invalid-spdx, unknown) to make review decisions easier
This logic applies to all dependencies (direct and transitive). Inferred licenses are never treated as authoritative over valid declared SPDX expressions.
`bash`
npm install
npm run build
- Node.js 14.14+
The simplest way to run Dependency Radar is via npx. It runs in the current directory and writes an HTML report to disk.
Run a scan against the current project (writes dependency-radar.html):
`bash`
npx dependency-radar
The scan command is the default and can also be run explicitly as npx dependency-radar scan.
Specify a project and output path:
`bash`
npx dependency-radar --project ./my-app --out ./reports/dependency-radar.html
Keep the temporary .dependency-radar folder for debugging raw tool outputs:
`bash`
npx dependency-radar --keep-temp
Skip npm audit and npm outdated (useful for offline scans):
`bash`
npx dependency-radar --offline
Output JSON instead of HTML report:
`bash`
npx dependency-radar --json
Open the generated report using the system default:
`bash`
npx dependency-radar --open
Show options:
`bash`
npx dependency-radar --help
- npm run build – generate SPDX/report assets and compile TypeScript to dist/npm run dev
- – run a scan from source (ts-node src/cli.ts scan)npm run scan
- – run a scan from the built output (node dist/cli.js scan)npm run dev:report
- – run the report UI dev servernpm run build:spdx
- – rebuild bundled SPDX identifiersnpm run build:report-ui
- – build report UI assetsnpm run build:report
- – rebuild report assets used by the CLI
- npm run fixtures:install – install core fixture dependenciesnpm run fixtures:install:all
- – install all fixture dependenciesnpm run fixtures:scan
- – scan the core fixture setnpm run fixtures:install:npm
- npm run fixtures:install:npm-heavy
- npm run fixtures:install:pnpm
- npm run fixtures:install:pnpm-hoisted
- npm run fixtures:install:yarn
- npm run fixtures:install:yarn-berry
- npm run fixtures:install:optional
- npm run fixtures:scan:npm
- npm run fixtures:scan:npm-heavy
- npm run fixtures:scan:pnpm
- npm run fixtures:scan:pnpm-hoisted
- npm run fixtures:scan:yarn
- npm run fixtures:scan:yarn-berry
- npm run fixtures:scan:optional
- npm run fixtures:scan:no-node-modules
-
- The target project must have dependencies installed (run npm install, pnpm install, or yarn install first).npm audit
- The scan runs on your machine and does not upload your code or dependencies anywhere.
- /pnpm audit/yarn npm audit and npm outdated/pnpm outdated perform registry lookups; use --offline for offline-only scans..dependency-radar
- A temporary folder is created during the scan to store intermediate tool output.--keep-temp
- Use to retain this folder for debugging; otherwise it is deleted automatically.
- If some per-package tools fail (common in large workspaces), the scan continues and reports warnings; missing sections are marked unavailable where applicable.
Dependency Radar writes a single HTML file (dependency-radar.html by default).
The file is fully self-contained and can be opened locally in a browser, shared with others, or attached to tickets and documentation.
Use --json to write the aggregated scan data as JSON (defaults to dependency-radar.json).
The JSON schema matches the AggregatedData TypeScript interface in src/types.ts. For quick reference:
`ts
export interface AggregatedData {
schemaVersion: '1.2'; // Report schema version for compatibility checks
generatedAt: string; // ISO timestamp when the scan finished
dependencyRadarVersion: string; // CLI version that produced the report
git: {
branch: string; // Git branch name, empty when unavailable/detached
};
project: {
projectDir: string; // Project path relative to the user's home directory (e.g. /Developer/app)
};
environment: {
nodeVersion: string; // Node.js version from process.versions.node
runtimeVersion: string; // Node.js runtime version from process.version
minRequiredMajor: number; // Strictest Node major required by dependency engines (0 if unknown)
platform?: string; // OS platform (process.platform)
arch?: string; // CPU architecture (process.arch)
ci?: boolean; // True when running in CI (process.env.CI === 'true')
packageManagerField?: string; // package.json packageManager field (e.g. pnpm@9.1.0)
packageManager?: 'npm' | 'pnpm' | 'yarn'; // Package manager used to scan
packageManagerVersion?: string; // Version of the package manager used to scan
toolVersions?: {
npm?: string;
pnpm?: string;
yarn?: string;
};
};
workspaces: {
enabled: boolean; // True when the scan used workspace aggregation
type?: 'npm' | 'pnpm' | 'yarn' | 'none'; // Workspace type if detected
packageCount?: number; // Number of workspace packages scanned
};
summary: {
dependencyCount: number; // Total dependencies in the graph
directCount: number; // Dependencies listed in package.json
transitiveCount: number; // Dependencies pulled in by other dependencies
};
dependencies: Record
}
export interface DependencyRecord {
package: {
id: string; // Stable identifier in the form name@version
name: string; // Package name from npm metadata
version: string; // Installed version from npm ls
description?: string; // Description from the installed package.json (if present)
deprecated: boolean; // True if the package.json has a deprecated flag
links: {
npm: string; // npm package page URL
repository?: string; // Repository URL (if present)
homepage?: string; // Homepage URL (if present)
bugs?: string; // Issue tracker URL (if present)
};
};
compliance: {
license: {
declared?: {
spdxId: string; // SPDX ID or expression from package.json
expression: boolean; // True when SPDX expression (AND/OR/WITH)
deprecated: boolean; // True if SPDX ID is deprecated
valid: boolean; // True if SPDX ID/expression is valid
};
inferred?: {
spdxId: string; // SPDX ID inferred from LICENSE text
confidence: 'high' | 'medium' | 'low'; // Heuristic confidence
};
exception?: {
id: string; // SPDX exception id
deprecated: boolean; // True if exception is deprecated
valid: boolean; // True if exception id is valid
};
status:
| 'declared-only'
| 'inferred-only'
| 'match'
| 'mismatch'
| 'invalid-spdx'
| 'unknown';
};
licenseRisk: 'green' | 'amber' | 'red'; // Risk classification derived from declared/inferred SPDX ids
};
security: {
summary: {
critical: number; // npm audit counts for critical issues
high: number; // npm audit counts for high issues
moderate: number; // npm audit counts for moderate issues
low: number; // npm audit counts for low issues
highest: 'low' | 'moderate' | 'high' | 'critical' | 'none'; // Highest severity present
risk: 'green' | 'amber' | 'red'; // Risk classification derived from audit counts
};
advisories?: Array<{
id: string; // GHSA identifier
title: string; // Human-readable advisory title
severity: 'low' | 'moderate' | 'high' | 'critical';
vulnerableRange: string; // Semver range
fixAvailable: boolean; // True if npm audit indicates a fix exists
url: string; // Advisory URL
}>;
};
upgrade: {
nodeEngine: string | null; // engines.node from the package.json (if present)
outdatedStatus?: 'current' | 'patch' | 'minor' | 'major' | 'unknown'; // Derived from npm outdated (if present)
latestVersion?: string; // npm latest version (present only when status is not current)
blockers?: Array<'nodeEngine' | 'peerDependency' | 'nativeBindings' | 'deprecated'>; // Reasons for upgrade friction
blocksNodeMajor?: boolean; // True if local signals indicate a node major bump is risky
};
usage: {
direct: boolean; // True if declared in package.json (dependencies/devDependencies/etc.)
scope: 'runtime' | 'dev' | 'optional' | 'peer'; // Scope inferred from the declaring root package(s)
depth: number; // Minimum dependency tree depth observed in npm ls
origins: {
rootPackageCount: number; // Number of direct roots that introduce this dependency
topRootPackages: Array<{ name: string; version: string }>; // Up to 10 root packages (name/version)
parentPackageCount: number; // Number of direct parents
topParentPackages: string[]; // Up to 5 direct parent ids (name@version)
workspaces?: string[]; // Workspace packages that declare/use this dependency
};
introduction?: 'direct' | 'tooling' | 'framework' | 'testing' | 'transitive' | 'unknown'; // Heuristic for why the dependency exists
runtimeImpact?: 'runtime' | 'build' | 'testing' | 'tooling' | 'mixed'; // Heuristic based on import locations
importUsage?: {
fileCount: number; // Number of project files importing this package (import graph)
topFiles: string[]; // Top import locations (bounded to 5)
};
tsTypes: 'bundled' | 'definitelyTyped' | 'none' | 'unknown'; // TypeScript type availability
};
graph: {
fanIn: number; // Number of packages that depend on this package
fanOut: number; // Number of packages this package depends on
subDeps?: {
// Declared outgoing dependency edges; values are tuples.
// tuple[0] = declared version range, tuple[1] = resolved dependency id or null if not installed.
// Only installed dependencies have full dependency records in the top-level list.
dep?: Record
dev?: Record
peer?: Record
opt?: Record
};
};
execution?: {
risk: 'amber' | 'red'; // Install-time risk (green implied when absent)
native?: true; // True if native bindings or build tooling are detected
scripts?: {
hooks: Array<'preinstall' | 'install' | 'postinstall' | 'prepare'>; // Lifecycle hooks detected
complexity?: number; // Heuristic complexity (stored only when high)
signals?: Array<
| 'network-access'
| 'dynamic-exec'
| 'child-process'
| 'encoding'
| 'obfuscated'
| 'reads-env'
| 'reads-home'
| 'uses-ssh'
>; // Review-worthy install-time signals (sparse)
};
};
}
`
For full details and any future changes, see src/types.ts.
Environment data includes Node.js version, OS platform, CPU architecture, and package manager versions.
No personal information, usernames, paths, or environment variables are collected.
The HTML report UI is developed in a separate Vite project located in report-ui/. This provides a proper development environment with hot reload, TypeScript support, and sample data.
Start the development server:
`bash`
npm run dev:report
This opens the report UI in your browser with sample data covering all dependency states (various licenses, vulnerability severities, usage statuses, etc.).
Build workflow:
1. Make changes in report-ui/ (edit style.css, main.ts, index.html)npm run build:report
2. Run to compile and inject assets into src/report-assets.tsnpm run build
3. Run to compile the full project (this runs build:report automatically)
File structure:
- report-ui/index.html – HTML template structurereport-ui/style.css
- – All CSS stylesreport-ui/main.ts
- – TypeScript rendering logicreport-ui/sample-data.json
- – Sample data for developmentreport-ui/types.ts
- – Client-side TypeScript typessrc/report-assets.ts` – Auto-generated file with bundled CSS/JS (do not edit directly)
-