To upgrade a dependency in a uv project, first update the lockfile with uv lock --upgrade-package 包名, then install and verify it with uv sync --locked. If the project’s declared version range excludes the target version, adjust the constraints in pyproject.toml first.
The common mistake is treating “synchronize the environment” as “find the latest version.” When uv sync leaves a package unchanged, uv is often following the existing lockfile.
This guide covers Python projects that already have a pyproject.toml. Examples use PowerShell; the core uv commands also work on Linux and macOS.
The examples use requests and pytest so you can try them in an isolated practice directory without connecting to a model API.
Documentation was checked on October 11, 2026. This guide does not establish upgrade compatibility for any specific AI project.
Identify which layer you want to update
“Update uv” can refer to three different kinds of objects. Identify the target first so you do not upgrade the tool and wonder why project dependencies stayed unchanged.
| Target | Typical operation | Main effect |
|---|---|---|
| The uv executable | Upgrade uv through its original installation channel | Package manager version |
| One project dependency | uv lock --upgrade-package requests |
Dependency resolution recorded in the lockfile |
| Allowed dependency range | uv add "requests>=2.32,<3" |
Project declaration, lockfile, and environment |
| All project dependencies | uv lock --upgrade |
All locked dependencies eligible for an upgrade |
| A tool installed through uv tool | uv tool upgrade 工具名 |
The tool’s isolated environment |
Do not use uv tool upgrade to update requests inside your project.
Upgrading the uv executable alone also does not automatically update packages in .venv.
Installed tools and project dependencies have separate maintenance scopes; see the uv tools guide.
What pyproject.toml, uv.lock, and .venv control
A dependency change involves three questions: which versions the project allows, which versions resolution selects, and which versions this machine actually has installed.
| File or directory | Purpose | Commit to Git? |
|---|---|---|
pyproject.toml |
Declare direct dependencies and allowed ranges | Yes |
uv.lock |
Store exact resolution results | Yes |
.python-version |
Record the project’s selected Python version | Usually |
.venv |
The environment installed on this machine | No |
For example, a project might declare:
|
|
This configuration permits a range of requests versions. It does not ask uv to install the latest version in that range on every run.
If uv.lock already locks a compatible version, a normal synchronization will generally keep using it.
This reduces surprises where a project works yesterday but breaks after a fresh installation today.
See the locking and syncing documentation for the underlying behavior.
Practice a single-package upgrade in a separate directory
First check that the tools are available:
|
|
Choose a directory name that does not already exist, so practice files stay out of your active repository. The following example uses a script-style project and does not require a Python package build backend.
|
|
If the required Python version is missing, uv may need to download an interpreter. On a restricted network, resolve download or interpreter discovery problems before diagnosing dependency conflicts. Python selection rules are explained in the official interpreter documentation.
Create main.py:
|
|
This code prepares a request without sending it over the network. It checks that the package imports and shows the version actually installed in the current environment.
|
|
Then record a practice baseline:
|
|
Before committing, confirm that .venv is not staged.
If you have not configured your Git identity, keep file copies for now; the Git rollback commands later require an existing commit.
Upgrade one package and inspect the changes
Run these commands in the project directory you just created:
|
|
Separating resolution from installation lets you inspect lockfile changes before changing the working environment.
If you prefer one operation, you can use uv sync --upgrade-package requests instead.
A “single-package upgrade” targets that package; it does not guarantee that only one lockfile entry changes. The new version may require different transitive dependencies, and the resolver must still find a combination that satisfies the entire project.
When reviewing the diff, focus on:
- Whether requests itself changed.
- Whether transitive dependencies were added or removed.
- Whether download sources still match project expectations.
- Whether another constraint keeps the target package at its previous version.
A newly created practice project will usually already have selected a currently available version. An upgrade that produces no diff can therefore be normal, rather than a failed command.
Use the project interpreter to check the installation:
|
|
The first command should print a path inside the project environment. If your editor shows a different version, check its selected Python interpreter first.
Why an upgrade can stay on an older version
Suppose the project declares:
|
|
An exact constraint permits only that version.
--upgrade-package does not override the project declaration.
After assessing compatibility and deciding to allow later versions, change the range explicitly:
|
|
By default, uv add updates the declaration, lockfile, and environment, so this step may already install a new package version.
Run it on a separate branch; it is not a read-only query.
If you only want to evaluate a particular version, declare that exact version and test it. Do not remove every upper bound merely to make resolution succeed: an existing bound may represent a known compatibility limit.
Other packages, Python versions, and platform conditions can also constrain the range. When resolution fails, identify the contradictory requirements in the error message. See dependency management for editing declarations and dependency groups.
Reserve a separate maintenance window for full upgrades
To update the whole project:
|
|
A full upgrade belongs in a dependency maintenance task, rather than a commit intended only to change page text. The larger the change, the harder it becomes to identify which package caused a regression.
Start with one application dependency and run acceptance checks, then handle development tools separately. Projects with native extensions, GPU runtimes, or model inference backends also need system library and driver checks. A lockfile records package resolution; it does not replace testing on actual hardware.
Choosing between –locked and –frozen
Both flags commonly appear in deployment commands, but they perform different checks.
| Command | Behavior | Use case |
|---|---|---|
uv lock --check |
Check that the lockfile matches the declaration | Pre-commit checks |
uv sync --locked |
Require an up-to-date lockfile, then synchronize | Deployment and reproduction |
uv run --locked python main.py |
Require an up-to-date lockfile, then run | Routine verification |
uv sync --frozen |
Use the existing lockfile without checking freshness | Workflows that validate the lockfile elsewhere |
If you change the dependency declaration but forget to update the lockfile, --locked helps expose the mismatch.
Skipping that check with --frozen does not establish that your new declaration took effect.
Environment cleanup is another distinction: uv sync uses exact synchronization by default and removes packages absent from the lockfile.
A debugging package manually installed into .venv may therefore disappear on the next synchronization.
Declare development tools you need to retain with uv add --dev.
Check a key behavior with a small test after upgrading
Create test_main.py:
|
|
Run:
|
|
This test covers the specific behavior of encoding request parameters. It does not prove that network connections, proxies, TLS, or application endpoints work. Real projects should cover their own critical paths, such as document parsing results, database operations, or API response structures.
If your project uses MinerU for document parsing, choose a fixed PDF and compare page counts, tables, and image references before and after upgrading.
Keeping a small regression input gives you stronger evidence than checking only whether import succeeds.
Recovering from a failed update
Keep the error logs and diff first, and check for work unrelated to the upgrade. The following commands discard uncommitted changes in these two files. Use them only when all those changes belong to this upgrade.
|
|
Restoring the declaration and lockfile together prevents them from contradicting each other. Run the tests again after synchronization to confirm that you restored a working state, not merely matching files.
If the upgrade has already been committed, find a known-good commit before restoring the corresponding file versions or reverting the upgrade commit.
Do not simply copy a colleague’s .venv: environment paths, platform binaries, and interpreter versions may differ.
Rolling back dependencies does not automatically undo database migrations or data changes made by the application. Upgrades that affect data formats require the application’s own backup and recovery procedure.
What if you only have requirements.txt?
Decide whether you want to keep the requirements workflow or migrate fully to a uv project. Do not combine both goals into a single upgrade command.
To retain the current workflow, install into a separate virtual environment:
|
|
If requirements already pins exact versions, this installation command does not remove those constraints. To migrate to the project workflow, initialize a project on a migration branch and import dependencies:
|
|
Importing a file generated by pip freeze can turn transitive dependencies into direct declarations.
After migration, distinguish packages your application actually uses from dependencies brought in by other packages.
Private indexes, editable installs, and platform conditions need separate review; see the official migration guide.
Export dependencies for deployments that still use pip
If you cannot move the whole project to uv yet, export from the lockfile:
|
|
Treat the exported file as a lockfile-derived artifact. After dependency changes, update the project and lockfile before exporting again, rather than maintaining two version lists manually.
This example project does not package itself. Installable application projects must also check whether the export includes the project itself or local path references. Deployment must provide the corresponding source code; copying requirements alone may not be enough. See the official export documentation for options.
Quick troubleshooting reference
| Symptom | Check first | Next step |
|---|---|---|
| Version unchanged after sync | A compatible version is already locked | Request a single-package upgrade explicitly |
| Still on an old version after upgrade | Exact constraints or restrictions from other packages | Review resolution and assess declaration changes |
| Terminal works, editor imports fail | Python interpreter path | Select the project’s .venv |
| Lockfile is correct, installation fails | Network, certificates, disk space, platform wheels | Keep the error and identify the download or build stage |
| Deployment reports a stale lockfile | Whether declaration and lockfile were committed together | Update and validate the lockfile on a development branch |
| Temporary tools disappear after sync | Whether tools are declared as dev dependencies | Manage them with uv add --dev |
A dependency update is complete when declarations are clear, the lockfile is consistent, the installed environment is correct, and critical application behaviors pass verification. Once you identify the target, start with one package and keep the diff and a recovery path.