# How to migrate from uv to pip


Moving a uv-managed project to [pip](https://pydevtools.com/handbook/reference/pip.md) is mostly an audit of [pyproject.toml](https://pydevtools.com/handbook/reference/pyproject.toml.md), not a rebuild of the project. [uv](https://pydevtools.com/handbook/reference/uv.md) consolidates Python interpreter installs, virtual environments, resolution, package installation, and lockfile generation into one tool, but if a project's metadata sticks to packaging standards, most of the substitutes are short. This how-to walks through the audit and the runtime equivalents: [pyenv](https://pydevtools.com/handbook/reference/pyenv.md) on macOS and Linux, the official python.org installer on Windows.

## Audit your pyproject.toml for uv-specific tables

Before exporting a lockfile, scan your `pyproject.toml` for settings under `[tool.uv]` and tables under `[tool.uv.*]`. Anything outside that namespace is already standardized and pip can read it. The settings that matter:

| Setting | Standard equivalent | Action |
| --- | --- | --- |
| `[tool.uv.dev-dependencies]` | `[dependency-groups]` ([PEP 735](https://pydevtools.com/handbook/explanation/what-is-pep-735.md)) | Move entries to `[dependency-groups]` so pip 25.1+ can install them with `pip install --group <name>`. |
| `[tool.uv.sources]` | None for git, path, or URL deps | Inline these as [direct-URL dependency specifiers](https://pydevtools.com/handbook/explanation/what-is-a-version-specifier.md) in `[project.dependencies]`, or document them so a teammate can reproduce the install. |
| `[tool.uv.workspace]` | None | A single pip install can target only one project at a time. Treat each member as its own install. |
| `[tool.uv.index]` | `pip.conf` or `--index-url` | Configure the alternative index in pip directly, not in `pyproject.toml`. |
| `[tool.uv.build-backend]` and `build-backend = "uv_build"` in `[build-system]` | Any [PEP 517 backend](https://pydevtools.com/handbook/explanation/what-is-pep-517.md) such as [hatchling](https://pydevtools.com/handbook/reference/hatch.md) | `uv_build` ships as a standalone PyPI package, so builds still work after removing uv. Swap the backend only if a complete exit from OpenAI tooling is the goal. |
| `tool.uv.constraint-dependencies` | `constraints.txt` plus `pip install --constraint` | Preserve these as pip constraints. Dropping them silently changes the resolved version set. |
| `tool.uv.override-dependencies` | None | Document or remove these before migrating. pip has no equivalent override mechanism. |

Runtime dependencies in `[project.dependencies]` and extras in `[project.optional-dependencies]` follow [PEP 621](https://pydevtools.com/handbook/explanation/what-is-pep-621-compatibility.md) and need no change. pip reads them natively.

## Install Python without uv

uv installs Python interpreters on demand. Without uv, the canonical replacements are pyenv on macOS and Linux and the official python.org installer on Windows.

Install pyenv (full instructions on the [pyenv reference](https://pydevtools.com/handbook/reference/pyenv.md)) and then install the Python version your project's `requires-python` allows:

```bash
pyenv install 3.13.0
pyenv local 3.13.0
python --version
```

`pyenv local` writes a `.python-version` file in the current directory so subsequent `python` invocations resolve to that interpreter.

Install Python from [python.org](https://www.python.org/downloads/windows/) or with `winget`. Both register the interpreter with the [`py` launcher](https://docs.python.org/3/using/windows.html#python-launcher-for-windows), which selects between installed versions:

```powershell
winget install Python.Python.3.13
py -3.13 --version
```

When creating the virtual environment in the next step, invoke `py -3.13 -m venv .venv` to pick the right interpreter. Once the venv is activated, plain `python` resolves to the version inside it.

## Create a virtual environment

Python's standard library ships [venv](https://pydevtools.com/handbook/reference/venv.md). It is enough for everything pip needs:

```bash
python -m venv .venv
source .venv/bin/activate
```

```powershell
py -3.13 -m venv .venv
.venv\Scripts\activate
```

The activated shell's `python` and `pip` now point inside `.venv/`. A deactivated shell falls back to the system interpreter.

## Generate a PEP 751 lockfile

uv's native lockfile, `uv.lock`, is not a portable format. Export it to [PEP 751](https://pydevtools.com/handbook/explanation/what-is-pep-751.md)'s standard `pylock.toml`, which any installer can consume:

```bash
uv export --format pylock.toml --no-default-groups > pylock.toml
```

`--no-default-groups` excludes whatever dependency groups uv would otherwise include by default, usually `dev`. Pass `--group <name>` if you also need a specific dependency group resolved into the lock.

The generated file starts with a header pip recognizes:

```toml
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.13"

[[packages]]
name = "cowsay"
version = "6.1"
```

## Install dependencies from the lockfile

Upgrade pip to 26.1 or newer inside the activated venv. The `-r pylock.toml` form was added in that release:

```bash
python -m pip install --upgrade pip
pip install -r pylock.toml --no-deps
```

`--no-deps` keeps the install strictly to what the lockfile records. Without it, pip can pull in additional transitive packages and silently drift from the locked set. The companion how-to on [installing from a pylock.toml lockfile with pip](https://pydevtools.com/handbook/how-to/how-to-install-from-a-pylock-toml-lockfile-with-pip.md) covers the experimental-feature warning, hash verification, and the filename rules pip enforces.

## Install a dependency group from pyproject.toml

For dev, test, or lint dependencies, pip can read `[dependency-groups]` directly out of `pyproject.toml`. No lockfile is involved:

```bash
pip install --group dev
```

This was added in pip 25.1. It resolves the named group fresh, so versions can shift between runs unless you also lock the group into a `pylock.toml`.

## Replace the rest with non-pip tools

A few uv features have no direct equivalent in pip alone. Each has a working substitute outside the pip toolchain:

- Inline-script metadata ([PEP 723](https://pydevtools.com/handbook/explanation/what-is-pep-723.md)) that `uv run script.py` resolves and executes. The closest substitutes are [pipx](https://pydevtools.com/handbook/reference/pipx.md) (`pipx run script.py`) and [pip-run](https://github.com/jaraco/pip-run).
- Persistent CLI tools installed with `uv tool install`. Use pipx (`pipx install <tool>`).
- Building and publishing wheels. uv's `uv build` and `uv publish` map to [build](https://pydevtools.com/handbook/reference/build.md) (`python -m build`) plus [twine](https://pydevtools.com/handbook/reference/twine.md) (`twine upload`). If `build-backend = "uv_build"` is set in `[build-system]`, swap it for a PEP 517 backend (the audit table covers this).
- Workspace-wide installs across multiple packages. There is no pip equivalent. Treat each workspace member as a separate project, or keep uv for the workspace orchestration even after switching the leaf installs.

If your project depends on any of these, plan their replacement before removing uv from your environment.

## Learn More

- [uv: A Complete Guide](https://pydevtools.com/handbook/explanation/uv-complete-guide.md) covers what uv does, how fast it is, the core workflows, and recent releases.
- [How to install from a pylock.toml lockfile with pip](https://pydevtools.com/handbook/how-to/how-to-install-from-a-pylock-toml-lockfile-with-pip.md) covers the install-side caveats in detail.
- [What is PEP 621?](https://pydevtools.com/handbook/explanation/what-is-pep-621-compatibility.md) walks through project metadata fields.
- [What is PEP 735?](https://pydevtools.com/handbook/explanation/what-is-pep-735.md) explains dependency groups.
- [What is PEP 751?](https://pydevtools.com/handbook/explanation/what-is-pep-751.md) covers the standardized lockfile format.
- [pip reference](https://pydevtools.com/handbook/reference/pip.md) and [pyenv reference](https://pydevtools.com/handbook/reference/pyenv.md) link to upstream docs.
