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

Kevin Renskers writing at [[loopwerk-blog|loopwerk.io]] on May 21, 2026: uv (the Rust-Python toolchain from Astral) has unambiguously won on speed and on collapsing the venv/pip/pyenv/pip-tools/poetry stack into one binary, but the routine project-maintenance commands — what you run weekly, not on day one — are weaker than what Poetry and pnpm shipped years ago. Three concrete UX gaps and one design default carry the argument.

## No dedicated outdated command

The closest equivalent of `pnpm outdated` is:

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

Which prints the entire dependency tree rather than filtering to outdated rows. A real `uv outdated` is the asked-for fix.

## Open-ended default version constraints

`uv add pydantic` writes `"pydantic>=2.13.4"` — no upper bound. A subsequent `uv lock --upgrade` is then free to land pydantic 3.x or higher. pnpm defaults to `^1.23.4`; Poetry to `>=1.23.4,<2.0.0`. Both at least pin a major-version line.

This is the same family of decision as Cargo's caret default and npm's `^` — and most ecosystems sit on the side of "respect SemVer at the upper bound by default." Renskers reads uv's default as the riskier one to ship with, given how many projects don't routinely audit their lockfile diffs. See [[default-version-bound-constraints]] for the broader concept.

A preview `--bounds major` flag exists:

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

which produces `pydantic>=2.13.4,<3.0.0`. Still opt-in, still preview-flagged.

## Inconsistent upgrade verb

To upgrade everything:

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

Two complaints. First, the obvious verb at the top level would be `uv update` or `uv upgrade`. Second, the CLI is internally inconsistent: `uv add` and `uv remove` are top-level commands, but there is no symmetric `uv lock --add` or `uv lock --remove`, so why does upgrade live under `uv lock`?

## Verbose per-package upgrades

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

Compare:

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

The flag repetition adds up across a half-dozen targeted upgrades.

## Where this lands

The author isn't asking anyone to switch off uv — speed and the unified toolchain are too valuable. The argument is narrower: uv is the new default for new projects but its maintenance commands haven't caught up to the prior generation, and the open-bound default in particular is the kind of decision that will quietly produce broken builds over years if it isn't addressed before uv's user base finishes consolidating on it.

It's worth reading alongside [[open-source-security-astral]], which documents Astral's strong supply-chain practices for *their own* releases — the contrast (rigorous for our releases, loose default for our downstream users' dependency constraints) is part of what makes this post stand out.

## See also

- [[loopwerk-blog]] — the source blog
- [[default-version-bound-constraints]] — the concept of upper-bound version defaults across npm/Cargo/Poetry/uv
- [[open-source-security-astral]] — Astral's own supply-chain posture; mentions uv's built-in cooldown support
- [[if-ai-writes-your-code-why-use-python]] — Mitchem's piece notes the OpenAI/Astral acquisition (March 2026) and uv saving Codex ~1M minutes of compute per week — context for why uv adoption is consolidating fast
