Dependency Check & Update — a fast, multi-ecosystem dependency updater written in Rust.
Like npm-check-updates, but for every language.
$ dcu
Checking Cargo.toml
toml_edit 0.22 -> 0.25.4
Checking .github/workflows/CI.yml
actions/checkout v4 -> v5
actions/setup-node v4 -> v5
Run dcu -u to upgrade
dcuis a short alias installed alongsidedependency-check-updates. Both commands are identical — use whichever you prefer.
No install needed — run straight from your package manager's ephemeral runner:
# Node.js ecosystem
bunx @dependency-check-updates/cli
npx @dependency-check-updates/cli
# Python ecosystem
uvx dependency-check-updates
pipx run dependency-check-updatesAll four accept the same flags described in Usage.
- Multi-ecosystem —
package.json,Cargo.toml,pyproject.toml, and.github/workflows/*.ymlall handled by a single binary - Format-preserving — surgical byte-range patching for JSON / YAML;
toml_editfor TOML. Your indentation, comments, trailing newlines, and key ordering stay intact - Fast — concurrent registry lookups across all manifests via
futures::join_all - Smart range checking — skips false positives where the resolved version already satisfies the current range (
^3already covers3.5.1) - Deep scan —
-drecursively finds manifests in monorepos, respecting.gitignore - ncu-compatible UX — the same flags you already know from
npm-check-updates - Short alias — type
dcuinstead ofdependency-check-updates; both are installed by every distribution - CI-friendly —
-e 2exits non-zero when updates exist;--format jsonemits machine-readable output
| Ecosystem | Manifest | Registry | Package |
|---|---|---|---|
| Node.js | package.json |
npm | @dependency-check-updates/cli |
| Rust | Cargo.toml |
crates.io | dependency-check-updates |
| Python | pyproject.toml |
PyPI | dependency-check-updates |
| GitHub Actions | .github/workflows/*.yml, action.yml |
GitHub Tags API | (built-in) |
- Discovers every
*.yml/*.yamlunder.github/workflows/and anyaction.yml/action.yamlat the repo root automatically. Composite actions nested under.github/actions/**/are picked up with-d. - Scans
uses: owner/repo@refdirectives. Refs without version digits —@main,@master, branch names, and full commit SHAs — are left untouched on purpose; they pin a moving target intentionally. - Tag prefix is preserved:
@v5updates to@v6(major float),@v5.1.0updates to@v6.0.0(full precision). Bare semver without thev(@1.2.3,@5) is recognised and tracked the same way. - Duplicate rows are collapsed in the output — if
actions/checkout@v5appears in 12 jobs, you see one row, not twelve. The patch engine still updates every occurrence in the file. - Rate limit: unauthenticated runs use GitHub's 60 req/hr ceiling. Hitting it produces an explicit error pointing to the fix — set
GITHUB_TOKEN(orGH_TOKEN) in your environment to raise the limit to 5 000 req/hr. - Tag fetch is bounded to the first 100 tags per action (newest-first). This comfortably covers every mainstream action; deliberately not paginating keeps API consumption predictable so deep scans don't spike into the rate-limit ceiling.
Every distribution below ships the exact same binary. Pick whichever matches your toolchain.
cargo install dependency-check-updatesInstalls commands: dependency-check-updates and dcu (short alias).
Permanent global install:
npm install -g @dependency-check-updates/cli
bun add -g @dependency-check-updates/cli
pnpm add -g @dependency-check-updates/cli
yarn global add @dependency-check-updates/cliInstalls commands: dependency-check-updates and dcu (short alias).
One-off execution (no install):
bunx @dependency-check-updates/cli [flags]
npx @dependency-check-updates/cli [flags]Permanent isolated install:
pipx install dependency-check-updates
uv tool install dependency-check-updatesInstall inside a virtualenv:
pip install dependency-check-updates
uv pip install dependency-check-updatesInstalls commands: dependency-check-updates and dcu (short alias).
One-off execution (no install):
uvx dependency-check-updates [flags]
pipx run dependency-check-updates [flags]Run from a directory containing at least one of package.json, Cargo.toml, pyproject.toml, or .github/workflows/*.yml. Every supported manifest in the current directory is auto-detected.
All examples below use the short dcu alias. The long form dependency-check-updates works identically.
# Check for outdated dependencies (read-only, nothing is written)
dcu
# Apply updates in place (format-preserving)
dcu -u
# Recursively scan subdirectories (monorepo-friendly, respects .gitignore)
dcu -d
dcu -d -uUsage: dcu [OPTIONS] [FILTER]...
| Flag | Description | Default |
|---|---|---|
[FILTER]... |
Positional package names to include (allowlist; repeatable) | (all) |
-u, --upgrade |
Write updated versions back to the manifest file | off |
-d, --deep |
Recursively scan subdirectories, respecting .gitignore |
off |
-t, --target <LEVEL> |
Version target: patch · minor · latest · newest · greatest |
latest |
-x, --reject <PATTERN> |
Exclude packages by name (repeatable) | — |
--manifest <PATH> |
Operate on a single specific manifest file | (auto) |
--format <FORMAT> |
Output format: table or json |
table |
-e, --error-level <N> |
1 = always exit 0 · 2 = exit 1 when updates exist (CI gate) |
1 |
-v, --verbose |
Increase verbosity: -v info · -vv debug · -vvv trace |
off |
-h, --help |
Print help | — |
-V, --version |
Print version | — |
| Value | Behavior |
|---|---|
patch |
Only patch bumps (e.g., 1.0.1 → 1.0.2) |
minor |
Patch + minor bumps (e.g., 1.0.0 → 1.1.0) |
latest |
Latest stable version; prereleases are skipped (default) |
newest |
Most recently published version by publish date |
greatest |
Highest version number, including prereleases |
# Target specific update level
dcu -t patch # patch only
dcu -t minor # minor + patch
dcu -t latest # default: latest stable
dcu -t greatest # include prereleases
# Filter packages — positional args act as an include-list
dcu react eslint # only check react and eslint
dcu -x typescript # exclude typescript
dcu -x typescript -x lodash
# Filter GitHub Actions by owner — same filter syntax works across ecosystems
dcu actions # only actions/checkout, actions/setup-node, …
# Operate on a specific manifest
dcu --manifest path/to/Cargo.toml
dcu --manifest apps/web/package.json
dcu --manifest .github/workflows/CI.yml
# Machine-readable output for scripting/CI
dcu --format json
# CI gate: exit 1 if any updates are available
dcu -e 2
# Verbose logging (accumulating)
dcu -v # info
dcu -vv # debug
dcu -vvv # trace
# Combining flags — recursive, patch-only upgrade in a monorepo
dcu -d -u -t patch
# GitHub Actions: pin a higher rate limit by exporting a token
GITHUB_TOKEN=ghp_xxx dcu -d -uEvery example above works identically via the ephemeral runners, too:
bunx @dependency-check-updates/cli # check
bunx @dependency-check-updates/cli -u # apply updates
bunx @dependency-check-updates/cli -d -t minor # deep scan, minor bumps
bunx @dependency-check-updates/cli react eslint # filter
npx @dependency-check-updates/cli --format json
uvx dependency-check-updates
uvx dependency-check-updates -d -u -t patch
pipx run dependency-check-updates --format jsonFollows the changepacks pattern — one crate per language ecosystem, with bridge crates for cross-language distribution:
.
├── crates/
│ ├── cli/ # Binary + async CLI orchestration (installs `dcu` + `dependency-check-updates`)
│ ├── core/ # Shared traits (ManifestHandler, RegistryClient, Scanner)
│ ├── node/ # Node.js: package.json parser + npm registry
│ ├── rust/ # Rust: Cargo.toml parser (toml_edit) + crates.io
│ ├── python/ # Python: pyproject.toml parser (toml_edit) + PyPI
│ └── github/ # GitHub Actions: workflow YAML parser + GitHub Tags API
├── bridge/
│ ├── node/ # napi-rs N-API binding → npm: @dependency-check-updates/cli
│ └── python/ # maturin bin binding → PyPI: dependency-check-updates
├── Cargo.toml # Workspace root
└── package.json # Bun workspace (build/lint/test scripts)
- JSON (
package.json): Surgical byte-range replacement — finds exact byte offsets of version values and replaces only those bytes. Indent, line endings, trailing newline, and key ordering are preserved byte-for-byte. - TOML (
Cargo.toml,pyproject.toml):toml_editdocument model preserves comments, table ordering, inline-table formatting, and whitespace. - YAML (
.github/workflows/*.yml,action.yml): Line-baseduses:scanning with byte-range replacement of only the@refportion. Anchors, comments, blank lines, and unrelated@main/@<sha>pins are never touched.
Each ecosystem crate implements two core traits from dependency-check-updates-core:
ManifestHandler— parse manifests, collect dependencies, apply format-preserving updatesRegistryClient— resolve versions from package registries with concurrency control
Before reporting an update, the resolver checks whether the selected version already satisfies the current range (e.g., ^3 already covers 3.5.1). This eliminates the false positives that plague naive string comparison.
Build prerequisites:
- Rust 1.85+ (stable toolchain)
- Bun 1.0+ (or Node.js 18+ with npm)
- Python 3.11+ with
maturin(only for the Python wheel step) - Windows: Visual Studio 2022 Build Tools (MSVC linker)
# First-time setup: install JS toolchain deps (@napi-rs/cli, etc.)
bun install
# Build everything (native CLI + napi .node + maturin wheel)
bun run build
# Dev build (faster, unoptimized)
bun run build:dev
# Lint (cargo clippy + rustfmt + bun workspace lints)
bun run lint
bun run lint:fix
# Test (cargo test --workspace + bun workspace tests)
bun run test
# Run CLI from source
bun run run -- --help
bun run run -- --manifest Cargo.toml -v
bun run run:release -- -d- npm-check-updates — the original
ncuthat inspired this tool's UX and flag design - changepacks — the workspace architecture pattern (
crates/*+bridge/*), multi-language bridge distribution via napi-rs and maturin, and the overall project structure
MIT