Skip to main content

Identify unnecessary dependencies in software projects

Project description

dep-audit

A CLI tool that identifies unnecessary dependencies in software projects. It answers the question existing tools don't ask: "which of your dependencies can you remove because the language itself now provides that functionality, the package is deprecated, or you never actually import it?"

What it finds

Category Examples
Stdlib backports pytzzoneinfo, tomlitomllib, lazy-staticstd::sync::LazyLock, go.uber.org/atomicsync/atomic
Zombie shims six, future — Python 2/3 compat layers; winapiwindows-sys
Deprecated packages pycryptopycryptodome, failurethiserror + anyhow, request (npm), github.com/dgrijalva/jwt-gogolang-jwt/jwt
Micro-utilities is-odd, is-even, left-pad — single expressions in native code
Unused dependencies Packages in your lockfile that are never imported in your source code

Supports Python, npm/Node.js, Cargo/Rust, and Go.

Install

# Run without installing (recommended for one-off scans)
uvx dep-audit scan .

# Install globally with pipx
pipx install dep-audit

# Install in a project
uv add --dev dep-audit
pip install dep-audit

Requires Python 3.11+. Zero runtime dependencies.

Quick start

# Scan the current directory
dep-audit scan .

# Scan a specific project
dep-audit scan /path/to/my-project

# Scan a GitHub repo (no clone needed)
dep-audit scan fastapi/fastapi
dep-audit scan django/django --ref stable/5.1.x

# Check a single package
dep-audit check pytz
dep-audit check lazy-static --ecosystem cargo
dep-audit check left-pad --ecosystem npm --offline
dep-audit check github.com/pkg/errors --ecosystem go

Ecosystems

Ecosystem Detection Lockfiles parsed
Python pyproject.toml, requirements.txt, setup.py uv.lock, poetry.lock, pyproject.toml, requirements.txt
npm package.json package-lock.json, yarn.lock, pnpm-lock.yaml, package.json
Cargo Cargo.toml Cargo.lock, Cargo.toml
Go go.mod go.mod

dep-audit detects the ecosystem automatically. In multi-language repos it scans each detected ecosystem separately.

Commands

scan — scan a project

dep-audit scan [path] [options]
Option Description
path Project root or owner/repo GitHub shorthand (default: .)
--format terminal|json|sarif Output format (default: terminal)
--offline Skip deps.dev API calls (faster, no network needed)
--target-version 3.11 Override the language version for stdlib detection
--ecosystem python Force a specific ecosystem instead of auto-detecting
--include-dev Include dev/test dependencies in the scan
--exit-code Exit with code 1 if any issues are found (for CI)
--min-confidence 0.8 With --exit-code: only fail on findings at or above this threshold (0.0–1.0)
--ignore PKG Suppress a package entirely — hidden from report (repeatable)
--known PKG Mark a finding as intentional — still shown, won't trigger --exit-code (repeatable)
--ref main Git ref for remote repos (branch, tag, or commit SHA)

check — look up a single package

dep-audit check <package> [--ecosystem python] [--offline]

Shows the package classification, what it can be replaced with, and live data from deps.dev (deprecated status, open advisories). Use --offline to skip the network call.

db — manage the junk database

dep-audit db list python          # List all entries grouped by type
dep-audit db list cargo           # List Cargo entries
dep-audit db show pytz            # Show entry for one package

# Discover new candidate entries from a project
dep-audit db export --discovered .
dep-audit db export --discovered fastapi/fastapi

cache — manage the API cache

dep-audit cache clear             # Delete ~/.cache/dep-audit/

Output formats

Terminal (default)

Results are grouped into four sections, most actionable first:

=== dep-audit: my-app (Python 3.12) ===

REMOVE — unused dependencies (zero effort):

  six ············································ not imported anywhere in project
      just delete from dependency list

REPLACE — stdlib alternatives available:

  pytz ··········································· stdlib_backport → datetime.zoneinfo (since 3.9)
      2 imports in src/utils.py:5

SIMPLIFY — micro-utilities (inline replacements):

  is-odd ········································· micro_utility → x % 2 !== 0
      3 imports across 2 files

DEPRECATED:

  pycrypto ······································· deprecated → pycryptodome

SUMMARY
  4 unnecessary packages found
  18 total production dependencies scanned
  1 zero-effort removal
  1 stdlib replacement
  1 micro-utility to inline
  1 deprecated

JSON

dep-audit scan . --format json | jq '.flagged[]'

Schema:

{
  "project": "my-app",
  "ecosystem": "python",
  "target_version": "3.12",
  "scan_mode": "local",
  "scanned_at": "2026-03-07T12:00:00+00:00",
  "production_deps": 18,
  "flagged": [
    {
      "name": "pytz",
      "version": "2024.1",
      "classification": "stdlib_backport",
      "confidence": 0.95,
      "is_direct": true,
      "imports": 2,
      "replacement": "datetime.zoneinfo",
      "stdlib_since": "3.9",
      "files": [{"path": "src/utils.py", "line": 5}]
    }
  ],
  "summary": {
    "zero_effort_removals": 1,
    "stdlib_replacements": 1,
    "micro_utilities": 0,
    "deprecated": 0,
    "total_transitive_freed": 2
  }
}

SARIF (GitHub Code Scanning)

dep-audit scan . --format sarif > dep-audit.sarif

SARIF 2.1.0 output for GitHub Code Scanning and any tool that consumes SARIF. Findings map to rule IDs:

Rule Classification Default level
DEP001 stdlib_backport warning
DEP002 zombie_shim warning
DEP003 deprecated error
DEP004 micro_utility note

Low-confidence findings (below 0.7) are downgraded to note.

Configuration

dep-audit reads config from the first file it finds, in priority order:

  1. .dep-audit.toml — standalone config, works for any ecosystem
  2. pyproject.toml[tool.dep-audit] section, Python projects only

CLI flags always override config values.

.dep-audit.toml (or [tool.dep-audit] in pyproject.toml):

ignore         = ["lodash", "uuid"]       # hide these packages from the report entirely
known          = ["typing-extensions"]    # show findings but don't fail --exit-code
target-version = "3.11"                   # language version for stdlib checks
ecosystem      = "python"                 # force a specific ecosystem
offline        = true                     # always skip deps.dev API
exit-code      = true                     # always use exit code mode
min-confidence = 0.8                      # only fail CI on findings >= this confidence

target-version is auto-detected from the project manifest:

Ecosystem Detected from Example
Python requires-python in pyproject.toml >=3.113.11
Rust package.rust-version in Cargo.toml 1.70
npm engines.node in package.json >=18.0.018.0
Go go directive in go.mod go 1.211.21

If the field is absent, dep-audit falls back to a safe default (Python: running interpreter, Rust: 1.80, Node: 22, Go: 1.21).

Inline ignores

Suppress a single package by adding a comment inline. Supported in requirements.txt:

requests==2.31.0
six==1.16.0  # dep-audit: ignore

Suppressing findings

Three ways to stop a finding from blocking CI, each with different intent:

ignore — hide completely

The package disappears from the report entirely. Use this for genuine false positives.

[tool.dep-audit]
ignore = ["typing-extensions"]  # needed for runtime type hints on 3.10
dep-audit scan . --ignore typing-extensions

known — acknowledge, don't block

The package still appears in the report but won't cause --exit-code to return 1. Use this for deliberate decisions — packages you know are flagged and have chosen to keep ("won't fix").

[tool.dep-audit]
known = ["six"]  # legacy code, migration planned for Q3
dep-audit scan . --known six

A note appears in stderr when known findings are present:

  1 known finding(s) suppressed from --exit-code: six

--min-confidence — raise the threshold

Only fail CI on findings above a confidence threshold. Useful during migrations where you want to enforce clear-cut findings (confidence 1.0) but tolerate uncertain ones.

dep-audit scan . --exit-code --min-confidence 0.9

CI integration

GitHub Actions

name: dep-audit
on: [push, pull_request]

jobs:
  dep-audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Scan dependencies
        run: uvx dep-audit scan . --exit-code --offline

GitHub Actions with Code Scanning (SARIF)

Upload findings as inline annotations on pull requests:

name: dep-audit
on: [push, pull_request]

jobs:
  dep-audit:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    steps:
      - uses: actions/checkout@v4
      - name: Scan dependencies
        run: uvx dep-audit scan . --format sarif --offline > dep-audit.sarif
      - name: Upload SARIF
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: dep-audit.sarif

GitLab CI

dep-audit:
  image: python:3.12-slim
  script:
    - pip install dep-audit
    - dep-audit scan . --exit-code --offline

Jenkins

stage('dep-audit') {
    sh 'uvx dep-audit scan . --exit-code --offline'
}

pre-commit

dep-audit is a pre-commit plugin. Add it to .pre-commit-config.yaml:

repos:
  - repo: https://github.com/zfoq/dep-audit
    rev: 0.5.0
    hooks:
      - id: dep-audit

The hook only runs when lockfiles or manifests change, so it doesn't slow down unrelated commits.

pre-commit install
pre-commit run dep-audit --all-files  # verify it works

To pass extra flags:

    hooks:
      - id: dep-audit
        args: [scan, ., --exit-code, --offline, --include-dev]

Offline vs online mode

By default dep-audit calls deps.dev to:

  • Resolve transitive dependencies — when you only have requirements.txt or pyproject.toml (no lockfile), it queries deps.dev to discover what each direct dep pulls in transitively.
  • Detect live deprecations — checks whether packages have been marked deprecated upstream, beyond what's in dep-audit's own database.

If your project has a full lockfile (uv.lock, package-lock.json, Cargo.lock), transitive deps are already in the file and the network resolution is skipped automatically. --offline only disables the live deprecation check.

Use --offline in CI/pre-commit for speed and determinism.

Remote scanning

Scan any public GitHub repo without cloning it:

dep-audit scan fastapi/fastapi
dep-audit scan https://github.com/pallets/flask
dep-audit scan django/django --ref stable/5.1.x
dep-audit scan expressjs/express --ecosystem npm --format json

Import usage analysis is skipped for remote scans since source code is not downloaded. Transitive dependency chains are still traced.

Cargo workspaces

For Cargo workspace repos, point dep-audit at a specific workspace member instead of the workspace root to get accurate direct-dependency attribution:

# Workspace root — scans all deps but can't tell which are direct for each crate
dep-audit scan .

# Workspace member — accurate results for that specific crate
dep-audit scan ./crates/my-crate
dep-audit scan ./tokio          # inside a tokio-style workspace

Go modules

Go module paths contain slashes (e.g. github.com/pkg/errors). Use the full module path when checking a single package:

dep-audit check github.com/pkg/errors --ecosystem go
dep-audit check github.com/dgrijalva/jwt-go --ecosystem go
dep-audit db show github.com/gogo/protobuf --ecosystem go

For multi-module repos, point dep-audit at the directory that contains the relevant go.mod:

dep-audit scan .                        # top-level go.mod
dep-audit scan ./cmd/myservice          # sub-module with its own go.mod

Import scanning walks all .go files under the project root, excluding vendor/ and testdata/ automatically.

Junk database

The database covers 141 packages across all ecosystems (Python: 43, npm: 57, Cargo: 21, Go: 20). Each entry is a TOML file in src/dep_audit/db/{ecosystem}/:

name        = "pytz"
ecosystem   = "python"
type        = "stdlib_backport"   # stdlib_backport | zombie_shim | deprecated | micro_utility
replacement = "datetime.zoneinfo"
stdlib_since = "3.9"
confidence  = 0.95
flags       = ["stdlib_backport: zoneinfo available since Python 3.9"]
validated   = 2026-01-15

Contributing entries

Found a package that should be flagged?

# Preview auto-generated stubs from a project scan
dep-audit db export --discovered .
dep-audit db export --discovered fastapi/fastapi

Review the output, fill in the details, and open a PR with the new .toml file.

Development

git clone https://github.com/zfoq/dep-audit
cd dep-audit
uv sync --group dev

# Run tests
uv run pytest

# Lint and type-check
uv run ruff check src/ tests/
uv run mypy src/

# Try it on itself
uv run dep-audit scan . --offline

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dep_audit-0.5.0.tar.gz (50.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dep_audit-0.5.0-py3-none-any.whl (104.9 kB view details)

Uploaded Python 3

File details

Details for the file dep_audit-0.5.0.tar.gz.

File metadata

  • Download URL: dep_audit-0.5.0.tar.gz
  • Upload date:
  • Size: 50.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dep_audit-0.5.0.tar.gz
Algorithm Hash digest
SHA256 d556fb976d471bbe1a44f211da4fcf49816ca6c2bba4d46c54e4eb423a91691e
MD5 594c3e0a9460e52b70282459d726cd6b
BLAKE2b-256 20da9273354ed9786521b2c1093cbfe1a963b14080b0b07f2ee4e56108a1bb4a

See more details on using hashes here.

Provenance

The following attestation bundles were made for dep_audit-0.5.0.tar.gz:

Publisher: publish.yml on zfoq/dep-audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dep_audit-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: dep_audit-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 104.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dep_audit-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 12ce96e0e9d0f0c2c1600ee0b64937be74a6f92ed2552f4e0e60a9239abfe41e
MD5 f73f8dc227b0b526d10dd352eae6b8a8
BLAKE2b-256 d62859049cb145538d333591174001cf9744b5f0fd54f5e787356dcfc15da03c

See more details on using hashes here.

Provenance

The following attestation bundles were made for dep_audit-0.5.0-py3-none-any.whl:

Publisher: publish.yml on zfoq/dep-audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page