@thestacklabs/depguard
v1.0.1
Published
Audit npm dependencies for health issues: maintenance, licenses, size, deprecation, and unused packages
Maintainers
Readme
@thestacklabs/depguard
Guard your npm dependencies. Audit maintenance status, license compatibility, bundle size, deprecation, and unused packages — all in a single command.
npx @thestacklabs/depguard depguard — [email protected]
Overall Health Score: 74/100
Healthy: 38 | Warning: 7 | Critical: 2 | Unused: 1
CRITICAL (2)
────────────────────────────────────────────────────────────
F [email protected] [dev] score: 5
! DEPRECATED: Use node-fetch or undici instead
! Last published 4.2 years ago
F [email protected] score: 0
! Package "left-pad" is installed but never imported
WARNINGS (7)
────────────────────────────────────────────────────────────
D [email protected] score: 42
~ Last published 2.8 years ago
~ Unpacked size: 4.2 MB
~ 37 direct dependenciesFeatures
- Maintenance — Flags stale/abandoned packages based on last publish date and maintainer count
- License — Detects incompatible licenses (GPL in MIT projects, missing licenses, SPDX expressions)
- Size — Flags bloated packages by unpacked size and dependency count
- Deprecation — Catches deprecated packages with their replacement messages
- Unused — Scans your source code to find installed packages that are never imported
- Health Score — Per-dependency score (0–100) with letter grades (A–F) and an overall project score
- Zero Dependencies — Uses only Node.js built-ins, nothing else
Install
# Run directly
npx @thestacklabs/depguard
# Or install globally
npm install -g @thestacklabs/depguard
# Or as a dev dependency
npm install --save-dev @thestacklabs/depguardRequires Node.js 18 or later.
CLI Usage
# Basic audit
npx @thestacklabs/depguard
# JSON output for CI/CD pipelines
npx @thestacklabs/depguard --json
# Fail CI if health score drops below threshold
npx @thestacklabs/depguard --threshold 60
# Show detailed per-analyzer breakdown
npx @thestacklabs/depguard --verbose
# Exclude devDependencies
npx @thestacklabs/depguard --no-dev
# Skip unused dependency scanning
npx @thestacklabs/depguard --no-unused
# Custom source directories for unused scan
npx @thestacklabs/depguard --src src,lib,app
# Sort by name or size instead of score
npx @thestacklabs/depguard --sort name
# Show only critical issues
npx @thestacklabs/depguard --filter critical
# Generate a config file
npx @thestacklabs/depguard initTip: Install globally with
npm i -g @thestacklabs/depguardto usedepguarddirectly withoutnpx.
All Options
| Flag | Description | Default |
|------|-------------|---------|
| --path, -p <path> | Path to package.json | ./package.json |
| --json | Output as JSON | false |
| --no-dev | Exclude devDependencies | includes dev |
| --include-peer | Include peerDependencies | false |
| --include-optional | Include optionalDependencies | false |
| --concurrency, -c | Max parallel registry requests | 8 |
| --threshold <n> | Min score; exit code 1 if below | none |
| --sort <field> | Sort by: score, name, size | score |
| --filter <level> | Show: critical, warning, all | all |
| --no-unused | Skip unused dependency scanning | scans |
| --src <paths> | Source dirs to scan (comma-separated) | src,lib,app,pages,components,. |
| --verbose, -v | Show per-analyzer score breakdown | false |
| --no-color | Disable colored output | colors on |
| --help, -h | Show help | |
| --version | Show version | |
Exit Codes
| Code | Meaning |
|------|---------|
| 0 | All dependencies above threshold (or no threshold set) |
| 1 | One or more dependencies below threshold |
| 2 | Execution error (e.g., package.json not found) |
Programmatic API
import { audit } from '@thestacklabs/depguard';
const report = await audit({
packageJsonPath: './package.json',
includeDev: false,
concurrency: 10,
config: {
thresholds: {
maintenance: { staleDays: 730 },
size: { maxUnpackedSize: 1_000_000 },
},
unused: {
srcPaths: ['src', 'lib'],
ignore: ['my-cli-tool'],
},
},
});
console.log(`Overall score: ${report.summary.overallScore}/100`);
for (const dep of report.dependencies) {
if (dep.score < 40) {
console.log(`${dep.name}@${dep.version}: ${dep.grade} (${dep.score})`);
for (const issue of dep.issues) {
console.log(` [${issue.severity}] ${issue.message}`);
}
}
}API Reference
audit(options?): Promise<AuditReport>
Main entry point. Analyzes all dependencies and returns a full report.
Options:
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| packageJsonPath | string | ./package.json | Path to package.json |
| includeDev | boolean | true | Include devDependencies |
| includePeer | boolean | false | Include peerDependencies |
| includeOptional | boolean | false | Include optionalDependencies |
| concurrency | number | 8 | Max parallel registry requests |
| skipUnused | boolean | false | Skip unused dependency scanning |
| srcPaths | string[] | ['src','lib',...] | Directories to scan for imports |
| config | PkgHealthConfig | {} | Override config (see below) |
| onProgress | function | — | Progress callback |
Returns: AuditReport
interface AuditReport {
projectName: string;
projectVersion: string;
projectLicense: string | null;
generatedAt: string;
summary: {
totalDependencies: number;
healthyCount: number; // score >= 70
warningCount: number; // score 40-69
criticalCount: number; // score < 40
unusedCount: number;
overallScore: number; // 0-100
};
dependencies: DependencyReport[];
}
interface DependencyReport {
name: string;
version: string;
dependencyType: 'production' | 'dev' | 'peer' | 'optional';
score: number; // 0-100
grade: 'A' | 'B' | 'C' | 'D' | 'F';
issues: Issue[];
details: {
maintenance: { lastPublished, daysSincePublish, maintainerCount, score };
license: { license, compatibility, score };
size: { unpackedSizeBytes, fileCount, directDependencies, score };
deprecation: { isDeprecated, message, score };
unused: { isUsed, score };
};
}Individual Analyzers
You can also use analyzers individually:
import {
analyzeDeprecation,
analyzeMaintenance,
analyzeLicense,
analyzeSize,
analyzeUnused,
scanUsedPackages,
RegistryClient,
} from '@thestacklabs/depguard';
// Fetch metadata for a single package
const client = new RegistryClient();
const metadata = await client.fetchPackage('express');
// Run individual analyzers
const deprecation = analyzeDeprecation(metadata);
const maintenance = analyzeMaintenance(metadata, {});
const license = analyzeLicense(metadata, { license: { projectLicense: 'MIT' } });
const size = analyzeSize(metadata, {});Configuration
Create a .depguardrc.json in your project root, or add a "depguard" key to your package.json.
Generate a default config:
depguard initConfig File
{
"include": {
"dev": true,
"peer": false,
"optional": false
},
"weights": {
"maintenance": 0.30,
"license": 0.20,
"size": 0.10,
"deprecation": 0.20,
"unused": 0.20
},
"thresholds": {
"maintenance": {
"staleDays": 730,
"criticalStaleDays": 1460
},
"size": {
"maxUnpackedSize": 2000000,
"maxDependencies": 30
},
"license": {
"allowed": [],
"blocked": ["GPL-3.0"]
}
},
"unused": {
"srcPaths": ["src", "lib", "app"],
"ignore": ["my-cli-tool"]
},
"ignore": ["internal-pkg"]
}Scoring
Each dependency gets a weighted score from 5 analyzers:
| Analyzer | Weight | What it checks | |----------|--------|----------------| | Maintenance | 30% | Days since last publish, maintainer count | | License | 20% | Compatibility with your project license | | Deprecation | 20% | Whether the package is deprecated | | Unused | 20% | Whether the package is actually imported in your code | | Size | 10% | Unpacked size and number of direct dependencies |
Grades: A (90+), B (75-89), C (60-74), D (40-59), F (below 40)
Unused Detection
The unused analyzer scans your source files (.js, .ts, .jsx, .tsx, .mjs, .cjs) for import and require statements. Packages in your package.json that are never imported are flagged.
Smart defaults — these are never flagged as unused:
- Type packages (
@types/*) - Build tools (
typescript,tsup,esbuild,webpack,vite,rollup) - Linters/formatters (
eslint,prettier,stylelintand their plugins) - Test runners (
vitest,jest,mocha) - Git hooks (
husky,lint-staged) - Packages referenced in
package.jsonscripts
Add custom exceptions with the unused.ignore config option.
CI/CD Integration
GitHub Actions
- name: Guard dependencies
run: npx @thestacklabs/depguard --json --threshold 60Pre-commit Hook
{
"scripts": {
"guard-deps": "depguard --threshold 70 --no-unused"
}
}Contributing
See CONTRIBUTING.md for guidelines on how to contribute to this project.
Author
Developed by Nachat Ra Sharma at thestacklabs.
License
MIT
