When the user asks to upgrade, bump, downgrade, or change the pinned version of a package in verl's uv flow, follow these steps.
verl uses one universal uv.lock for the whole project. Every version is pinned in pyproject.toml; the lockfile is generated from it. Never hand-edit uv.lock — edit the pin in pyproject.toml and re-lock. For the full background, read the "Upgrade or modify dependencies" section of docs/start/install.rst and the header comment in pyproject.toml.
1. Locate the version pin
Version pins live in two places in pyproject.toml:
- Per-backend extras under
[project.optional-dependencies]—verl-core(shared runtime deps) and the backend extrasvllm,sglang,fsdp,megatron,cpu. A package likevllm==0.20.2is pinned inside thevllmextra. - Global overrides under
[tool.uv].override-dependencies—transformers,numpy, andkernelsare force-pinned project-wide here, overriding whatever the extras / upstreams request.
Grep for the package to find every occurrence; it may appear in several extras (e.g. torch==2.11.0 is repeated across vllm, sglang, fsdp, megatron, cpu).
2. Edit the pin
Change the version specifier in every place it appears.
- If the package is
transformers,numpy, orkernels, update it in[tool.uv].override-dependenciesas well as the extras — the override wins, so a stale value there silently defeats the extra. - Shared deps (
torch,transformers, ...) span multiple extras that must agree because they share one torch "world"; bump them together, not in a single extra.
3. Handle coupled pins (critical for vllm / torch bumps)
Some upgrades ripple into other pins. Check and update as needed:
- torch world:
vllm,sglang,fsdp,megatronall pin the sametorch/torchvision/torchaudioand route to thepytorch-cu130index ([tool.uv.sources]). A vllm/sglang bump that needs a new torch must move all of them in lockstep. - flash-attn wheel: the prebuilt URL in
[tool.uv.sources].flash-attnis matched to a specific(CUDA, torch, cp-abi)tuple. If you change torch / CUDA / Python, swap the URL for a matching wheel from the prebuild releases, or fall back to a source build (addflash-attnto[tool.uv].no-build-isolation-packageand listflash-attn==<ver>directly in the extra). Only one direct URL is allowed per package across the whole lock (uv#13073). - dependency-metadata: git-source packages (
apex,transformer-engine,megatron-core,mbridge,flash-attn) have hand-written[[tool.uv.dependency-metadata]]blocks and[tool.uv.sources]revs. If you bump one of these, update both itsversionand its gittag/revtogether.
4. Re-lock and validate
Regenerate the single lockfile, then materialize a .venv to confirm it resolves and imports:
# from the verl/ project root, after editing pyproject.toml:
python manage_envs.py lock # or: uv lock
python manage_envs.py sync vllm fsdp # sync a relevant conflict-free combo
python manage_envs.py run vllm fsdp -- python -c "import vllm; print(vllm.__version__)"
Pick a sync combo that exercises the changed package. Mutually exclusive extras (see [tool.uv].conflicts) can't be synced together; manage_envs.py validates this and prints the conflict sets. Run python manage_envs.py list to see all extras and conflict rules.
The uv flow targets Linux + Python 3.12, on x86_64 and aarch64 — uv sync fails on macOS or other platforms. (uv lock only resolves, so it runs anywhere; it always writes both arches, since [tool.uv].environments declares a marker for each.) If there is no uv on the host, regenerate the lock inside Docker with docker build -f docker/Dockerfile.uv.cu130 --target=lock ... and copy uv.lock back out.
A bumped version must have wheels for both arches, or the lock will fail or silently drop the package on one of them. Check the package's PyPI files (or the wheelhouse index for apex / flash-attn / transformer-engine) for an aarch64 wheel alongside the x86_64 one before pinning. If only one arch has it, gate it with a platform_machine marker inside the extra rather than forking the extra — see the environments comment in pyproject.toml.
5. Sync Dockerfile system pins (after the re-lock)
uv.lock is the source of truth for the cuDNN / NCCL apt-deb versions baked into the Docker images. After a bump that moves torch (and thus its bundled nvidia-* wheels), reconcile them:
grep -E 'nvidia-(cudnn|nccl)-cu1[23]' uv.lock
# then update CUDNN_VERSION / NCCL_VERSION in docker/Dockerfile.uv.cu130 to match
6. Commit
Always commit the manifest and the lockfile together so the repo stays reproducible:
git add pyproject.toml uv.lock # plus docker/Dockerfile.uv.cu130 if you touched it
Quick ad-hoc test (non-persistent)
If the user only wants to try a version in an existing .venv without re-locking:
source .venv/bin/activate
uv pip install -U vllm # or: uv pip install vllm==<ver>
Warn the user this is not captured in uv.lock and the next manage_envs.py sync reverts it. For a lasting change, use steps 1–6.