Skip to content

How to Migrate from conda to uv

This guide converts a conda project (defined by an environment.yml) into a uv project built on pyproject.toml and a uv.lock lockfile. The result: a project-local .venv, a cross-platform lockfile, and resolves and installs that finish in seconds instead of minutes.

Unlike the conda-to-pixi migration, there is no --import flag. uv reads from PyPI, not conda channels, so the migration is a re-declaration of your dependencies rather than a file conversion.

Confirm uv is the right target

uv fits a project whose dependencies all live on PyPI as wheels: NumPy, pandas, scikit-learn, matplotlib, SciPy, and most of the pure-Python scientific stack ship working wheels. For that stack, uv is the leaner choice and the fastest resolver available.

uv installs Python packages only. It cannot install the conda-only, non-Python dependencies conda-forge is built to provide:

  • CUDA toolkits and GPU libraries resolved from conda-forge
  • The standalone gdal package and its osgeo.gdal bindings, HDF5, or PROJ
  • Compilers and non-Python languages (R, Julia) sharing one environment

If your environment.yml pulls any of those from conda-forge, migrate to pixi instead, which keeps the project-local, lockfile-driven workflow while installing from conda-forge. See uv vs pixi vs conda for scientific Python and when should I choose pixi over uv? to confirm the call.

Translate environment.yml to pyproject.toml

Start from a typical scientific environment.yml:

environment.yml
name: analysis
channels:
  - conda-forge
dependencies:
  - python=3.12
  - numpy
  - pandas
  - scikit-learn
  - matplotlib

Create a uv project in the same directory, pinning the Python version from the python= line:

$ uv init --name analysis --python 3.12
Initialized project `analysis`

Add every package from the dependencies: list in one command. Packages under a pip: section in environment.yml go through the same uv add (they were already PyPI packages):

$ uv add numpy pandas scikit-learn matplotlib
Resolved 19 packages in 321ms
Installed 15 packages in 102ms
 + matplotlib==3.11.0
 + numpy==2.5.1
 + pandas==3.0.3
 + scikit-learn==1.9.0
 + scipy==1.18.0

uv writes the packages into [project.dependencies] and captures exact resolved versions in a lockfile (uv.lock):

pyproject.toml
[project]
name = "analysis"
requires-python = ">=3.12"
dependencies = [
    "matplotlib>=3.11.0",
    "numpy>=2.5.1",
    "pandas>=3.0.3",
    "scikit-learn>=1.9.0",
]

Conda pins like numpy=1.26 become a version constraint if you pass it: uv add "numpy==1.26.*". Drop the pin to take the latest compatible release, as shown here.

Map conda commands to uv

The day-to-day workflow translation:

Conda command uv equivalent Notes
conda create -n analysis python=3.12 uv init --python 3.12 uv creates the .venv on the first uv add or uv sync
conda activate analysis uv run <command> uv run python script.py uses the project venv with no activation step
conda install scipy uv add scipy Adds to pyproject.toml and updates uv.lock
pip install some-pkg uv add some-pkg Both come from PyPI; one command now
conda env export uv lock uv.lock records the exact resolved versions
conda env create -f environment.yml uv sync Recreates .venv from pyproject.toml + uv.lock
conda list uv pip list Lists packages installed in the project venv

To activate the environment the conda way instead of prefixing with uv run, source the venv directly: source .venv/bin/activate on macOS and Linux, or .venv\Scripts\activate on Windows.

Verify the environment

Recreate the environment from the lockfile and import the packages:

$ uv sync
$ uv run python -c "import numpy, pandas; print(numpy.__version__, pandas.__version__)"
2.5.1 3.0.3

If uv sync reports No pyproject.toml found in current directory or any parent directory, you ran it outside the project. cd into the directory that holds pyproject.toml and try again.

Remove the old conda environment

Once the uv project works, tear down the conda environment:

conda deactivate
conda env remove -n analysis

Commit pyproject.toml and uv.lock so teammates reproduce the environment with uv sync; uv already added .venv/ to .gitignore. Keep the environment.yml around only while other team members finish switching.

Learn more

Last updated on