How to Migrate from conda to uv
This guide converts a conda environment into a uv project built on pyproject.toml and a uv.lock lockfile. The result: a project-local .venv, a cross-platform lockfileA file that records the exact version of every installed package, so everyone working on the project gets identical installs.
, 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 PyPIThe Python Package Index, the public repository where Python packages are published and downloaded from. "pip install requests" fetches requests from PyPI.
Learn more →
, not conda channels, so the migration re-declares your dependencies rather than converting a file.
If you inherited a conda environment and want to keep working in it rather than replace it, start with Take over an existing conda environment.
Confirm uv can replace your environment
uv fits a project whose dependencies all live on PyPI as wheelsA prebuilt Python package file (.whl) that installs without compiling anything. The standard distribution format for Python packages. Learn more → : NumPy, pandas, scikit-learn, matplotlib, SciPy, and most of the 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
gdalpackage and itsosgeo.gdalbindings, HDF5, or PROJ - Compilers and non-Python languages (R, Julia) sharing one environment
If your environment 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.
Leaving the defaults channel behind also removes a licensing obligation. Is conda actually free? covers who owes Anaconda a paid license.
Recover your dependency list
If the environment has an environment.yml, read the package names from it:
name: analysis
channels:
- conda-forge
dependencies:
- python=3.12
- numpy
- pandas
- scikit-learn
- matplotlib
- pip:
- seabornIf the environment was built by hand with conda install, ask conda for the specs you asked for:
$ conda env export -n analysis --from-history
name: analysis
channels:
- conda-forge
dependencies:
- python=3.12
- numpy
- pandas
prefix: /opt/conda/envs/analysis
Warning
--from-history reports only what conda installed. Packages you installed with pip inside the environment never appear, so a migration based on that output alone silently drops them. List them separately before you delete anything:
$ conda list -n analysis | grep pypi
matplotlib 3.11.1 pypi_0 pypi
seaborn 0.13.2 pypi_0 pypi
That listing includes dependencies pulled in automatically. Carry over the packages you installed on purpose; uv resolves the rest.
Create the uv project
Create the project with --bare, which writes a pyproject.toml and nothing else. The default uv init builds a distributable package: a src/ layout, a [build-system], and a console-script entry point, none of which an analysis environment needs. Pass the Python version from the python= line so requires-python matches:
$ uv init --bare --name analysis --python 3.12
Initialized project `analysis`
Pin the interpreter so uv builds the .venv against it rather than the newest Python on the machine:
$ uv python pin 3.12
Pinned `.python-version` to `3.12`
Note
Pass --python to uv init before running uv python pin. Without it, uv init sets requires-python to the newest interpreter on the machine, and pinning an older version fails as incompatible with that floor.
Add your dependencies
Pass every package name from your recovered list to a single uv add. Packages from a pip: section go through the same command, since they were already PyPI packages:
$ uv add numpy pandas scikit-learn matplotlib seaborn
Using CPython 3.12.10 interpreter at: /usr/local/bin/python3.12
Creating virtual environment at: .venv
Resolved 20 packages in 427ms
Prepared 18 packages in 2.14s
Installed 18 packages in 242ms
+ matplotlib==3.11.1
+ numpy==2.5.1
+ pandas==3.0.5
+ scikit-learn==1.9.0
+ scipy==1.18.0
+ seaborn==0.13.2
uv writes the packages into [project.dependencies] and captures exact resolved versions in a lockfile (uv.lock):
[project]
name = "analysis"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"matplotlib>=3.11.1",
"numpy>=2.5.1",
"pandas>=3.0.5",
"scikit-learn>=1.9.0",
"seaborn>=0.13.2",
]Drop conda’s pins unless something depends on them. A conda pin translates to a version constraint (uv add "pandas==2.2.*"), but old pins carried across wholesale tend to conflict with each other and fail to resolve. Start unpinned, confirm your code runs, then re-pin only what breaks.
uv init --bare writes no .gitignore. Add .venv/ to yours so the environment stays out of version control.
Map conda commands to uv
| Conda command | uv equivalent | Notes |
|---|---|---|
conda create -n analysis python=3.12 |
uv init --bare --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 tree --depth 1 |
Shows your declared dependencies; uv pip list shows everything installed |
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.
Move your Jupyter kernel
A conda environment registered as a Jupyter kernel needs an equivalent kernel pointing at the new .venv:
$ uv add --dev ipykernel
$ uv run ipython kernel install --user --name=analysis
Installed kernelspec analysis in /Users/you/Library/Jupyter/kernels/analysis
Select the analysis kernel in Jupyter. Remove the stale conda kernel with jupyter kernelspec remove <old-name>. See How to run a Jupyter notebook with uv for launching notebooks from the project.
Verify the environment and remove the old one
Recreate the environment from the lockfile and import the packages:
$ rm -rf .venv
$ uv sync
Using CPython 3.12.10 interpreter at: /usr/local/bin/python3.12
Creating virtual environment at: .venv
Resolved 50 packages in 1ms
Installed 44 packages in 462ms
$ uv run python -c "import numpy, pandas; print(numpy.__version__, pandas.__version__)"
2.5.1 3.0.5
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.
Once the uv project works, tear down the conda environment:
conda deactivate
conda env remove -n analysisCommit pyproject.toml and uv.lock so teammates reproduce the environment with uv sync. Keep the environment.yml around only while other team members finish switching.