TL;DR:
- Pixi is a fast, cross-platform package manager built on conda-forge that adds lockfiles, project-level environments, and PyPI integration
- It replaces the conda/pip combination for Python and data science workflows with a single tool and reproducible environments
- Installation is a single curl command; migration from existing conda environments takes minutes
If you’ve worked in Python data science or scientific computing for any length of time, you’ve had the conda experience: slow environment solves, mysterious dependency conflicts, environments that work on your machine but not in CI, and the endless pain of getting CUDA, cuDNN, and PyTorch to all agree on the same version simultaneously.
Pixi (from prefix.dev) is the most significant rethink of this workflow in years. It’s built on top of the conda-forge ecosystem but adds a lockfile-based approach that makes environments truly reproducible, integrates PyPI packages natively, and runs noticeably faster than conda or mamba for most operations.
What Pixi actually does differently
The key shifts from traditional conda:
Per-project environments instead of named global environments. With conda, you create environments that live in your home directory (~/miniconda3/envs/myenv). With Pixi, environments live inside the project directory (.pixi/). This means environments travel with the project, and you can’t accidentally activate the wrong environment for the wrong project.
A lockfile. pixi.lock pins every dependency — including transitive ones — to exact versions. This is standard in JavaScript (package-lock.json, pnpm-lock.yaml) and Rust (Cargo.lock), but conda has historically lacked it. With a lockfile, pixi install on any machine produces an identical environment. This is transformative for reproducible research and reliable CI.
Native PyPI integration. One of conda’s long-standing friction points is that not everything is on conda-forge — you often end up with a mixed conda/pip environment that breaks easily. Pixi supports PyPI packages directly in pixi.toml, with proper dependency resolution that considers both conda and PyPI packages together.
Speed. Pixi uses rattler (a reimplementation of conda’s solver in Rust) and downloads packages in parallel. Environment creation that takes 3–5 minutes in conda typically takes 30–60 seconds in Pixi.
Installation
# macOS and Linux
curl -fsSL https://pixi.sh/install.sh | bash
# Windows (PowerShell)
iwr -useb https://pixi.sh/install.ps1 | iex
Pixi is a single binary with no runtime dependencies. No Python interpreter required to install it.
Starting a new project
mkdir my-ml-project && cd my-ml-project
pixi init
This creates pixi.toml — Pixi’s equivalent of pyproject.toml for environment management. Add packages:
pixi add python numpy pandas scikit-learn matplotlib jupyter
pixi add --pypi some-pypi-only-package
The pixi.toml tracks your dependencies; pixi.lock is generated automatically and should be committed to version control.
Run commands in the environment without activating it:
pixi run python my_script.py
pixi run jupyter lab
Or activate a shell:
pixi shell
The pixi.toml format
A minimal pixi.toml for a data science project:
[project]
name = "my-ml-project"
version = "0.1.0"
channels = ["conda-forge"]
platforms = ["linux-64", "osx-arm64", "win-64"]
[dependencies]
python = ">=3.11,<3.13"
numpy = ">=1.26"
pandas = ">=2.2"
scikit-learn = ">=1.4"
matplotlib = ">=3.8"
jupyter = ">=1.0"
[pypi-dependencies]
some-pypi-only-package = ">=1.0"
[tasks]
train = "python src/train.py"
evaluate = "python src/evaluate.py"
notebook = "jupyter lab"
The [tasks] section lets you define project-specific scripts that run in the environment — similar to npm scripts. pixi run train runs the training script without needing to activate the environment first.
Multiple environments in one project
Pixi supports defining multiple environments in a single project, which is useful for separating dev dependencies from production dependencies, or for testing against multiple Python versions:
[feature.dev.dependencies]
pytest = ">=8.0"
black = ">=24.0"
ruff = ">=0.3"
[feature.cuda.dependencies]
pytorch-gpu = ">=2.2"
cudatoolkit = ">=12.0"
[environments]
default = ["dev"]
production = {features = [], no-default-feature = true}
cuda = ["cuda", "dev"]
Then run against a specific environment:
pixi run --environment cuda python train_gpu.py
This is particularly useful for ML workflows where you want a CPU environment for development and a GPU environment for training runs.
Migrating from conda
If you have an existing environment.yml:
pixi init --import environment.yml
Pixi will convert your dependencies to pixi.toml format. Review the output and run pixi install to verify everything resolves. For complex environments with many pinned versions, you may need to relax some constraints — Pixi’s solver is stricter about consistency than conda’s in some cases, which is the point.
CI integration
Because Pixi uses a lockfile, CI is straightforward:
# GitHub Actions
- name: Install Pixi
uses: prefix-dev/setup-pixi@v0.8.0
- name: Install dependencies
run: pixi install
- name: Run tests
run: pixi run pytest
pixi install reads the lockfile and installs the exact same environment as your local machine. No solver runs in CI, no version surprises.
What Pixi doesn’t replace
Pixi is a project environment manager, not a Python version manager. If you need to manage multiple Python interpreter versions (similar to pyenv), use mise alongside Pixi — they complement each other rather than conflict. Pixi manages the project’s dependencies; mise handles the toolchain versions available on your system.
Pixi also isn’t a substitute for container-based isolation if you need hard process boundaries for security or production deployment. Think of it as the development environment tool, with Docker handling production packaging separately.
For Python-only projects without any native scientific dependencies, uv is often faster and simpler — it doesn’t bring the conda-forge channel infrastructure. But for anything that needs BLAS, LAPACK, CUDA, HDF5, GDAL, or other native libraries, Pixi’s conda-forge integration makes those dependencies manageable in a way that pip alone never has been.