# uv is fantastic, but its package management UX is a mess

# uv is fantastic, but its package management UX is a mess

By Kevin Renskers · May 21, 2026 · loopwerk.io

Astral's uv is rightfully celebrated for speed and for collapsing the Python toolchain (venv, pip, pyenv, pip-tools, poetry) into one Rust binary. Day-to-day project maintenance — finding outdated packages, updating them, keeping the lockfile honest — is where the experience drops below what Poetry and pnpm already deliver.

## No `uv outdated`

There is no dedicated outdated command. The closest incantation is:

```
$ uv tree --outdated --depth 1
```

It dumps the whole dependency tree rather than just the rows that are behind. Compare:

```
$ pnpm outdated
```

…which gives a clean filtered table.

## Open-ended version constraints by default

`uv add pydantic` writes this into `pyproject.toml`:

```toml
dependencies = [
    "pydantic>=2.13.4",
]
```

No upper bound. The next `uv lock --upgrade` is free to jump pydantic to 3.x, then 4.x, then 100.x. pnpm and Poetry default to `^1.23.4` (caret) or an explicit `>=1.23.4,<2.0.0` range, which at least respects SemVer's major-version line.

## `uv lock --upgrade`, not `uv update`

To update everything:

```
$ uv lock --upgrade
```

The author flags two things: (1) "update" or "upgrade" would be a more obvious verb at the top level; (2) the CLI is internally inconsistent — `uv add` and `uv remove` are top-level, but there is no `uv lock --add` or `uv lock --remove`, so it's unclear why upgrade lives under `uv lock`.

Per-package upgrades repeat the flag:

```
$ uv lock --upgrade-package pydantic --upgrade-package httpx --upgrade-package uvicorn
```

vs.

```
$ pnpm update pydantic httpx uvicorn
```

## The `--bounds` escape hatch

A recent preview flag adds opt-in upper bounds:

```
$ uv add pydantic --bounds major
```

Produces `pydantic>=2.13.4,<3.0.0`. Still opt-in, still preview-flagged, doesn't fix what existing projects already have.

## Practical dilemma

Today's choices for a uv user:

1. Hand-edit `pyproject.toml` after every `uv add` to add upper bounds.
2. Accept that `uv lock --upgrade` can silently introduce major-version breakage.

## What would fix it

- A real `uv outdated` that filters its output.
- A top-level `uv update [packages...]` without flag repetition.
- Default constraint behavior that respects SemVer boundaries (or at least makes the choice explicit at `uv init` time).

## Conclusion

> "the developer experience for maintaining a project is currently a step backward from the tools that came before it"

Until the gaps close, lockfile diffs need careful review.
