Skip to main content

upd logo

upd

crates.io PyPI CI License: MIT

A fast dependency updater for Python, Node.js, Rust, Go, Ruby, .NET, Terraform, GitHub Actions, pre-commit, and Mise projects, written in Rust.

Quick Start

# Preview changes without modifying files (default)
uvx upd

# Apply updates
uvx upd --apply

# Or with pipx
pipx run upd --apply

Features

  • Multi-ecosystem: Python, Node.js, Rust, Go, Ruby, .NET, Terraform, GitHub Actions, pre-commit, Mise/asdf
  • Dry-run by default: nothing is written without --apply
  • Fast: parallel registry requests, with a 24-hour version cache
  • Constraint-aware: respects >=2.0,<3 (Python), ~> 7.1 (Ruby), and ^2.0.0 / ~2.0.0 (npm, Cargo)
  • Format-preserving: keeps formatting, comments, and structure
  • Update filters: --only-bump, --max-bump, --package, --lang, or approve one by one with -i
  • Major warnings: breaking changes are flagged with (MAJOR)
  • Pre-release aware: updates pre-releases to newer pre-releases
  • Cooldown: hold back releases younger than N days, against supply-chain attacks
  • Security auditing: OSV vulnerability scanning with auto-fix and SARIF output
  • Check mode: exit 1 if updates are available (for CI and pre-commit)
  • Gitignore-aware: honors .gitignore and prunes hidden directories, without missing the dotfiles it updates
  • Private registries: authentication for PyPI, npm, Cargo, Go, and GitHub
  • Config file: include or exclude paths, ignore packages, and pin versions via .updrc.toml

Installation

From crates.io

cargo install upd

# or with cargo-binstall (faster, pre-built binary)
cargo binstall upd

From PyPI

pip install upd
# or with uv
uv pip install upd

If you installed an earlier release under the old distribution name, migrate once with pip uninstall upd-cli && pip install upd. The upd-cli command remains available as a compatibility alias.

From source

git clone https://github.com/rvben/upd
cd upd
cargo install --path .

Usage

# Preview changes without modifying files (default when no --apply)
upd

# Apply updates to files
upd --apply

# Limit to specific files or directories
upd --apply requirements.txt pyproject.toml

# Approve updates one by one
upd -i

# Only the packages you name
upd -p requests,flask

# Cap the bump level (allow patch + minor, skip major). Updates above the
# ceiling are reported as held back, never as up to date, and do not
# change the exit code.
upd --max-bump minor

# Restrict to exactly one level (repeatable, comma-separated)
upd --only-bump major

# One ecosystem at a time: python, node, rust, go, ruby, dot-net,
# terraform, actions, pre-commit, mise, annotated
upd --lang python

# Exit 1 if anything is outdated (for CI and pre-commit)
upd --check

# Regenerate lockfiles after writing
upd --apply --lock

# Print the effective configuration and exit
upd --show-config

upd --help lists every flag; Stability documents the ones that are contractual, and upd schema emits the whole interface as JSON.

Dry-run by default: upd without --apply only previews changes. Pass --apply to write updates. --check, --dry-run, and --interactive do not require --apply.

VCS-root scoping: When no path argument is given, upd scans from the nearest .git ancestor directory rather than the current working directory. This prevents accidental rewrites when CWD is a subdirectory inside a repository.

Commands

upd --version      # Print version
upd self-update    # Check for upd updates
upd clean-cache    # Clear the version cache
upd align          # Align versions across files (--check exits 1 on misalignment)
upd audit          # Scan for known vulnerabilities (exit 6 if found)
upd schema         # Machine-readable interface description

Example Output

.pre-commit-config.yaml:37: Would update pre-commit/pre-commit-hooks v4.6.0 → v6.0.0 (MAJOR)
.github/workflows/ci.yml:16: Would update actions/checkout v4 → v6 (MAJOR)
.github/workflows/ci.yml:18: Would update jdx/mise-action v2 → v4 (MAJOR)
.mise.toml:8: Would update rust 1.91.1 → 1.94.0
Cargo.toml:33: Would update clap 4.5.53 → 4.6.0
Cargo.toml:36: Would update tokio 1.48.0 → 1.50.0

Would update 6 package(s) (2 major, 3 minor, 1 patch) in 4 file(s), 8 up to date

Output includes clickable file:line: locations (recognized by VS Code, iTerm2, and modern terminals).

Version Constraints

upd respects version constraints in your dependency files:

Constraint Behavior
>=2.0,<3 Updates within 2.x range only
^2.0.0 Updates within 2.x range (npm/Cargo); never crosses the major bound
~2.0.0 Updates within 2.0.x range (npm); ~2.0.0 (Cargo) stays within 2.0.x
~> 7.1 Updates within 7.x range (Ruby pessimistic)
>=2.0 Updates to any version >= 2.0
==2.0.0 Updates the exact pin to the latest version (e.g. ==2.0.0==3.1.5). To freeze a package, use [pin] or ignore in .updrc.toml.

An update moves the lower bound and leaves every other clause where the author wrote it, so >=1.0, <2.0 becomes >=1.5.0, <2.0. A constraint is an unordered set of clauses, so the lower bound is found wherever it sits (<2.0, >=1.0 answers alike), and an upper bound is honored when picking the new version: the release chosen is the newest one the constraint already admits.

npm ranges keep the shape they were written in. A comparator range (">=1.0.0 <2.0.0") and a hyphen range ("4.17.0 - 4.18.0") each keep their ceiling. A wildcard or partial range takes its ceiling from its own floor, like a caret, so it follows the newest release and the whole shape moves with it: "4.3.x" becomes "4.4.x" and "^1.2" becomes "^3.1", never a fully written version. npm lets a comparator stand apart from the version it applies to, and that spacing is part of the shape: ">= 1.2.7 < 1.3.0" is read as the range it is and comes back spaced the same way. npm's tilde has two spellings and "~>1.2.3" means what "~1.2.3" does, ceiling included; each comes back spelled the way it was written.

An npm spec that names no published version is left alone and reported nowhere: "*", a dist-tag ("latest", "next", "beta"), and the workspace:, file:, link:, npm:, git+ssh: and github:owner/repo forms all resolve somewhere other than a release on the registry, so there is no version to compare and nothing an update could move.

Bounds that are not floors

Only an inclusive lower bound names the version a project is on, so only that bound is raised. >1.2.3 names the one version its author refuses, <3 and <=3 are ceilings, != 1.5 is an exclusion, and an OR range ("^1 || ^2") has no single branch to edit. None of them is a floor, so none of them is moved. They are checked against the registry and reported anyway:

Outcome Reported as
The constraint admits the newest release Up to date
The newest release has outgrown it A warning naming the release and the constraint
The spec cannot be read at all An error, exit 2

The last row is the point of the other two: a dependency nothing looked at must not be counted as up to date, and a constraint that has quietly frozen a dependency should say so rather than pass under a green tick.

Annotated Version Pins

Files without a dependency-manifest format can carry a trailing annotation:

shinyhub_version: "0.11.16"  # upd: pypi shinyhub

Directory walks scan annotations in Makefile, makefile, GNUmakefile, justfile, Justfile, *.mk, *.sh, and *.bash. Any file passed explicitly is scanned as annotated. To add other files to normal repository discovery, use repository-relative globs in .updrc.toml:

include = ["ansible/roles/*/vars/*.yml", "docker-compose.yml"]
exclude = ["**/archive/**"] # exclude wins over include

An include never changes a recognized manifest's parser: for example, a matching main.tf remains Terraform. Use --verbose to diagnose an upd: marker in an otherwise undiscovered UTF-8 text file up to 1 MiB.

Version Precision

By default, upd preserves version precision from the original file:

# Original file has 2-component versions
flask>=2.0        →  flask>=3.1        (not 3.1.5)
django>=4         →  django>=6         (not 6.0.0)

# Original file has 3-component versions
requests>=2.0.0   →  requests>=2.32.5

# GitHub Actions major-only tags
actions/checkout@v3  →  actions/checkout@v4  (not @v4.2.0)

Use --full-precision to always output full semver versions:

upd --full-precision
flask>=2.0        →  flask>=3.1.5
django>=4         →  django>=6.0.0
requests>=2.0.0   →  requests>=2.32.5

Version Alignment

In monorepos or projects with multiple dependency files, the same package might have different versions:

# requirements.txt
requests==2.28.0

# requirements-dev.txt
requests==2.31.0

# services/api/requirements.txt
requests==2.25.0

upd align updates every occurrence to the highest version found:

upd align              # Align all packages to highest version
upd align --dry-run    # Preview changes
upd align --check      # Exit 1 if misalignments (for CI)
upd align --lang python # Align only Python packages

It only aligns within one ecosystem, skips packages with upper bound constraints (e.g. >=2.0,<3.0) to avoid breaking them, and ignores pre-release versions when finding the highest version.

Pre-commit Integration

Add upd to your .pre-commit-config.yaml:

repos:
  - repo: https://github.com/rvben/upd-pre-commit
    rev: v0.0.24
    hooks:
      - id: upd-check
        # Optional: only check specific ecosystems
        # args: ['--lang', 'python']

Available hooks:

Hook ID Description
upd-check Fail if any dependencies are outdated
upd-check-major Fail only on major (breaking) updates

Both hooks run on pre-push by default. Uses language: python which installs upd from PyPI automatically, so no manual installation is needed.

Documentation

Everything you look up rather than read lives in docs/.

Releases

Vership workflow, publication guarantees, automated integration pins, and safe retry procedures. → docs/releases.md

Supported files

Every file upd discovers, per ecosystem, plus annotated version pins in files it does not otherwise understand. → docs/ecosystems.md

Security auditing

OSV vulnerability scanning, --fix-audit, SARIF output, and CI integration. → docs/audit.md

Configuration file

.updrc.toml discovery order and every key it accepts. → docs/configuration.md

Cooldown (minimum release age)

Hold back versions published less than N days ago, per ecosystem. → docs/configuration.md#cooldown-minimum-release-age

Caching

Where the 24-hour version cache lives and how to clear or bypass it. → docs/configuration.md#caching

Environment variables

Every variable upd reads, in one table. → docs/configuration.md#environment-variables

Private repositories

Credential detection for PyPI, npm, Cargo, Go, and GitHub, including private indexes declared in pyproject.toml. → docs/private-registries.md

GitHub pull requests

Run any supported dependency updates as one rolling GitHub PR, with immutable Action SHA verification, validation, artifact reporting, and opt-in auto-merge. → docs/github-actions.md

GitLab merge requests

Run scheduled dependency updates as one rolling GitLab MR, with validation, lease-protected branch updates, and explicitly opt-in GitLab-native auto-merge. → docs/gitlab.md

Stability

The stable CLI surface, exit codes, --lock commands, and output guarantees. → docs/stability.md

Development

# Build
make build

# Run tests
make test

# Lint
make lint

# Format
make fmt

# All checks
make check

License

MIT

Download files

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

Source Distribution

upd-0.8.0.tar.gz (670.6 kB view details)

Uploaded Source

Built Distributions

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

upd-0.8.0-py3-none-win_amd64.whl (3.6 MB view details)

Uploaded Python 3Windows x86-64

upd-0.8.0-py3-none-musllinux_1_2_x86_64.whl (5.5 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

upd-0.8.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (5.5 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

upd-0.8.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (5.6 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

upd-0.8.0-py3-none-macosx_11_0_arm64.whl (3.2 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

upd-0.8.0-py3-none-macosx_10_12_x86_64.whl (3.4 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file upd-0.8.0.tar.gz.

File metadata

  • Download URL: upd-0.8.0.tar.gz
  • Upload date:
  • Size: 670.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.3

File hashes

Hashes for upd-0.8.0.tar.gz
Algorithm Hash digest
SHA256 26213401910768429a39ba2d892a09caed8af8e061a8069be76e056dc6d06f2a
MD5 0843c84447051eeb3485be791d56caf6
BLAKE2b-256 5322f44116f3432f7869c99ea7c61ec5082b9ea2ae2e1bafa04d504abaaf4248

See more details on using hashes here.

File details

Details for the file upd-0.8.0-py3-none-win_amd64.whl.

File metadata

  • Download URL: upd-0.8.0-py3-none-win_amd64.whl
  • Upload date:
  • Size: 3.6 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.3

File hashes

Hashes for upd-0.8.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 40de5e0db1ad8997b727d364714add014ae3a8eab96b2b4e533fd87502e74a69
MD5 b4c51dc19ebec9a9387499ed3eb8304d
BLAKE2b-256 ab0daa0479ab57c3215c3fb02fbb0c3799207a6c5142afce2cdd8d81e79edca8

See more details on using hashes here.

File details

Details for the file upd-0.8.0-py3-none-musllinux_1_2_x86_64.whl.

File metadata

  • Download URL: upd-0.8.0-py3-none-musllinux_1_2_x86_64.whl
  • Upload date:
  • Size: 5.5 MB
  • Tags: Python 3, musllinux: musl 1.2+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.3

File hashes

Hashes for upd-0.8.0-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 9bd1a5360942ba1a4a1e2a3c7d5c783a158cec143226c48d436bea6fa10e9a23
MD5 ef04035bb25ba7d8bf89bb705456736c
BLAKE2b-256 a58e15b90efa1b5277e400c997d1e5700490c6e8cf714330b5c75a01b8689ac7

See more details on using hashes here.

File details

Details for the file upd-0.8.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for upd-0.8.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c78633e95e44f87c6917ee17e76faeb0e679fd5b810d23ef0972bc6a7faf0d53
MD5 7e444df436cacea242512ff901afde46
BLAKE2b-256 823168c754506eec75b1e115734192b4fe4b172dbe05c99736e3bb8137544be8

See more details on using hashes here.

File details

Details for the file upd-0.8.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for upd-0.8.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 66ea57ba8ba9084a44679fa59beb270216c5cc210f90e6df3cc27e789d7589d5
MD5 f51213dc47ff319191f1799ff4a3f931
BLAKE2b-256 85fb1c0c84bb00e45dc6d05b5d1468101d0ff3d45c8dfb0ab3b1871cdb8d6cd3

See more details on using hashes here.

File details

Details for the file upd-0.8.0-py3-none-macosx_11_0_arm64.whl.

File metadata

  • Download URL: upd-0.8.0-py3-none-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 3.2 MB
  • Tags: Python 3, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.3

File hashes

Hashes for upd-0.8.0-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 1aac53bbf270da6c0e13d98bdb516e342feaa68c0b1922069771c8e481754a2a
MD5 415c193200ca06b70f7d58d0a6452eb2
BLAKE2b-256 d95542d550e90887b2da6f4b93561fcd05d1853fb8193c8838490a158776095b

See more details on using hashes here.

File details

Details for the file upd-0.8.0-py3-none-macosx_10_12_x86_64.whl.

File metadata

  • Download URL: upd-0.8.0-py3-none-macosx_10_12_x86_64.whl
  • Upload date:
  • Size: 3.4 MB
  • Tags: Python 3, macOS 10.12+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.3

File hashes

Hashes for upd-0.8.0-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 db8755a7237fa3256085ca5d7dc24f2554b3a43162ae5a22c6d133e4633f938f
MD5 4be8fadcef35765de78811f30cff6bc6
BLAKE2b-256 b26d3b2241c407f02f953cab9b3de02d60c6017a1e67edd8815efa6c3e11e7d7

See more details on using hashes here.

Release history Release notifications | RSS feed

0.11.5

7 files

0.11.4

7 files

0.11.3

7 files

0.11.2

7 files

0.11.1

7 files

0.11.0

7 files

0.10.4

7 files

0.10.3

7 files

0.10.2

7 files

0.10.1

7 files

0.10.0

7 files

0.9.2

7 files

0.9.1

7 files

0.9.0

7 files

0.8.8

7 files

0.8.7

7 files

0.8.6

7 files

0.8.5

7 files

0.8.4

7 files

0.8.3

7 files

0.8.2

7 files

0.8.1

7 files

This release

0.8.0 This release

7 files

0.7.1

7 files

0.7.0

7 files

0.6.5

7 files

0.6.4

7 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page