{"slug": "uv-is-fantastic-but-its-package-management-ux-is-a-mess", "title": "Uv is fantastic, but its package management UX is a mess", "summary": "While uv is praised for its speed and ability to replace multiple Python tools, its package management user experience is criticized as clunky compared to alternatives like pnpm and Poetry. Key issues include the lack of a simple `uv outdated` command, unsafe default version constraints that lack upper bounds, and a cumbersome upgrade process requiring repetitive `--upgrade-package` flags. The article notes that uv has recently introduced a `--bounds` flag to address the unsafe default constraints.", "body_md": "uv is fantastic, but its package management UX is a mess\nAstral’s uv has taken the Python world by storm, and for good reason. It is blisteringly fast, handles Python versions with ease, and replaces a half-dozen tools with a single binary. I’ve written multiple articles about it before.\nGetting started with a new Python project using uv and adding your first dependencies is very easy. But once you move past the initial setup and into the maintenance phase of a project, i.e. checking for outdated packages and performing routine upgrades, the CLI starts to feel surprisingly clunky compared to its peers like pnpm or Poetry.\nFinding outdated packages\nIn my JavaScript projects, if I want to see what needs an update, I run:\n$ pnpm outdated\nThis gives a clean, concise list of outdated packages, their current version, the latest version, and the version allowed by your constraints.\nIn uv, there is no uv outdated\n. Instead, you have to memorize the following mouthful:\n$ uv tree --outdated --depth 1\nThe output is also a problem. It doesn’t just show you what is outdated; it shows you your entire top-level dependency tree, with a small annotation next to the ones that have updates available. If you have 50 dependencies and only two are outdated, you still have to scan a 50-line list.\nPoetry isn’t much better with its command poetry show --outdated\n, but at least it only shows actual outdated packages.\nUnsafe version constraints by default\nThis is the most significant philosophical departure uv takes from pnpm and Poetry, and it’s a dangerous one for production stability.\nHow pnpm/Poetry handle it\nWhen you add a package using pnpm add\n, it writes it to package.json\nusing the caret requirement (^1.23.4\n). The caret at the beginning means that any 1.x.x version is allowed, but it will not update to 2.0.0.\nPoetry does the same by default, using a format like >=1.23.4,<2.0.0\n. I find this less readable than ^1.23.4\n, but the effect is the same.\nIn both cases, updates are safe by default. You can run pnpm update\nor poetry update\nevery morning and have high confidence that your build won’t break due to a major API change (assuming the packages you depend on respect SemVer).\nHow uv handles it\nWhen you run uv add pydantic\n, it inserts this into your pyproject.toml\n:\ndependencies = [\n\"pydantic>=2.13.4\",\n]\nNote the lack of an upper bound. In the eyes of uv, pydantic version 2, 3, and 100 are all perfectly acceptable.\nThis means uv updates are unsafe by default. If you run a bulk update, you aren’t just getting bug fixes; you are opting into every breaking change published by every maintainer in your dependency graph.\nThe bad UX of the upgrade command\nThe commands to actually perform an update in uv feel like they were designed for machines rather than humans.\nIf you want to update everything in pnpm or Poetry, it’s a simple pnpm update\nor poetry update\ncommand. In uv, you use:\n$ uv lock --upgrade\nBecause of the “no upper bounds” issue mentioned above, uv lock --upgrade\nis a nuclear option. It will upgrade every single package in your lockfile to their absolute latest versions, ignoring SemVer safety. And this includes deep, nested dependencies you’ve never heard of! Good luck, better hope there are no breaking changes anywhere.\nOnce you realize this is too risky, you’ll want to upgrade only specific packages. After scouring the subpar output of uv tree --outdated --depth 1\nto find them, the syntax becomes a repetitive chore.\nHow pnpm does it:\n$ pnpm update pydantic httpx uvicorn\nHow uv does it:\n$ uv lock --upgrade-package pydantic --upgrade-package httpx --upgrade-package uvicorn\nHaving to repeat the --upgrade-package\nflag for every single item is a huge hassle when you want to update a bunch of packages. I don’t understand why the UX of uv’s commands is so poor.\nThere is hope: the bounds flag\nLuckily uv has recently introduced a --bounds\noption for uv add\n:\n$ uv add pydantic --bounds major\nThis produces the safer pydantic>=2.13.4,<3.0.0\nconstraint we’ve come to expect. However, this is currently an opt-in feature. You have to remember to type it every time, and as of now, it is considered a preview feature.\nUntil --bounds major\n(or a similar configuration) becomes the default behavior, uv users are essentially forced to choose between two bad options:\n- Manually edit\npyproject.toml\nto add upper bounds for every single dependency. - Live in fear that\nuv lock --upgrade\nwill accidentally pull in a breaking major version change.\nWhat I’d like to see\nI love uv. Its speed is transformative, and the way it manages Python toolchains is second to none. But as a package manager, the developer experience for maintaining a project is currently a step backward from the tools that came before it.\nWe need a dedicated uv outdated\ncommand that filters noise, a more ergonomic update\ncommand that doesn’t require repeating flags, and default version constraints that respect the sanity of Semantic Versioning.\nUntil then, I’ll be double-checking every single line of my lockfile changes with a healthy dose of suspicion.", "url": "https://wpnews.pro/news/uv-is-fantastic-but-its-package-management-ux-is-a-mess", "canonical_source": "https://www.loopwerk.io/articles/2026/uv-ux-mess/", "published_at": "2026-05-21 20:56:36+00:00", "updated_at": "2026-05-22 08:30:19.624481+00:00", "lang": "en", "topics": ["developer-tools", "open-source"], "entities": ["uv", "Astral", "Poetry", "pnpm"], "alternates": {"html": "https://wpnews.pro/news/uv-is-fantastic-but-its-package-management-ux-is-a-mess", "markdown": "https://wpnews.pro/news/uv-is-fantastic-but-its-package-management-ux-is-a-mess.md", "text": "https://wpnews.pro/news/uv-is-fantastic-but-its-package-management-ux-is-a-mess.txt", "jsonld": "https://wpnews.pro/news/uv-is-fantastic-but-its-package-management-ux-is-a-mess.jsonld"}}