Switching from conda to pixi

Despite many improved and fully-compatible substitutes of conda existing today, pixi has become my preferred replacement. This post explains why, and how to get started.

Why conda was (previously) chosen

Before talking about leaving conda, it is worth acknowledging why conda became the dominant choice for bioinformaticians in the first place. It had many irreplaceable features that still benefit us nowadays.

Cross-language. Most package managers are language-specific: pip and uv for Python, renv for R, cargo for Rust. Conda is different. It manages packages in any language, including pre-compiled C/C++ binaries, Python libraries, R packages, and command-line tools—all from the same interface. For bioinformaticians who routinely chain together Python scripts, R analyses, and compiled aligners in a single workflow, this is invaluable.

The bioconda community. The bioconda channel is one of the most remarkable community efforts in computational biology. It hosts over 9,000 bioinformatics tools—samtools, STAR, DESeq2, snakemake, nextflow, and thousands more—maintained by contributors across the field. Because bioconda is built on top of conda’s packaging infrastructure, any tool in bioconda is one conda install away, with dependencies handled automatically. This dramatically lowered the barrier to installing and sharing scientific software.

Cross-platform support. Conda supports Linux, macOS, Windows, be it x86 or ARM. It matters in collaborative environments where team members use different operating systems and analyses eventually need to run on HPC clusters.

These strengths made conda the de facto standard. The frustrations that followed were not because conda was a bad idea—they were because the ecosystem grew faster than the original implementation could handle.


Background: the birth of pixi

To understand what pixi is and why it exists, it helps to trace where it came from.

Back in 2019, Wolf Vollprecht, a scientific software engineer at QuantStack, was frustrated by how slow conda had become. As the conda-forge channel grew to tens of thousands of packages, the “Solving environment…” spinner could spin for minutes—or never finish at all. In a blog post titled Making conda fast again, he introduced mamba: a drop-in conda replacement that reimplemented the dependency solver in C++, backed by libsolv (the same solver used by RPM-based Linux distributions). The speedup was dramatic. Mamba became widely adopted in the scientific and bioinformatics communities, and Anaconda eventually adopted libmamba as conda’s default solver in 2022–2023 (since conda version 23.10.0).

Vollprecht also started boa, a faster replacement for conda-build, but it never fully took off. The real successor came later.

Around 2022, Vollprecht left QuantStack to found prefix.dev, a company focused specifically on package management. There, together with engineer Bas Zalmstra, the team built rattler: a suite of Rust libraries that implement the full conda package ecosystem—reading metadata, solving dependencies, downloading, and installing—without needing Python at all. Rattler proved so solid that in October 2024, it was moved into the official conda GitHub organization, a signal of broad community trust.

On top of rattler, prefix.dev built two tools. pixi, launched publicly on August 16, 2023, is the environment and dependency manager—the one this post is about. rattler-build, also built on rattler, is the package builder: a fast, Rust-based replacement for conda-build (and the archived boa) that compiles source recipes into conda packages. If you maintain bioconda or conda-forge recipes, rattler-build is worth knowing about; for most users who only consume packages, pixi is the relevant tool. The motivating blog post for the pixi launch was called Let’s stop dependency hell.

The lineage in brief:

conda (before v23.10, Python, slow solver)
  └─> mamba (2019) — C++ reimplementation
        └─> boa (2020) — faster conda-build, later archived
rattler (2022) — Rust crate library
  ├─> pixi (2023) — project-based environment manager
  └─> rattler-build (2023) — conda package builder, successor to boa

Why leave conda?

No real global packages

The base environment of conda is not truly “global”. Once you activate another environment, you lose access to packages installed in base. As a bioinformatician, there are tools I need everywhere and every day—samtools, bedtools, minimap2—and it would be nice to have those genuinely available system-wide without switching between environments. Besides, if conda is managed by your server admin, it will be a nightmare to update/install packages into the base environment without root privilege.

Slow speed and dependency conflicts

Once an environment grows large (or sometimes even when it is not that large), conda can take a very long time to resolve dependencies. It is not uncommon to wait half an hour before conda either finds a solution or reports a conflict. Mamba solves things much faster, but it can still throw dependency conflicts or silently remove existing packages to work around them. (Nevertheless, I sincerely recommend mamba if someone does not want to completely jump ship from conda).

A real cross-language package manager

To my knowledge, conda (and now pixi) is the only package manager that works across multiple programming languages. uv is excellent, but Python-only. cargo is one of my favorites, but Rust only. Bioinformaticians regularly work with software written in Python, R, C++, Rust, and sometimes even Perl. Having one tool that handles all of these—while also pulling from bioconda and conda-forge—matters. Pixi also has better pip compatibility than conda, which only partially supports mixing pip-installed packages. (This stackoverflow discussion is really helpful on conda & pip.)

Open source and free

Pixi is open-source and free with no licensing restrictions (BSD 3-Clause). Conda itself is open-source, but the defaults channel is not free for commercial use, which can create uncertainty depending on your institution’s situation. Pixi uses conda-forge by default, which is fully open.

Reproducibility

Conda has no built-in lockfile. Reproducing an environment from an environment.yml does not guarantee the same package versions will be resolved—channels change over time, and conda env create can silently produce a different set of packages than what was originally installed. conda list --export does not always produce a reproducible file. Tools like conda-lock exist to fill this gap, but they are a separate step that most people skip.

Pixi generates a pixi.lock automatically on every pixi add or pixi install. This file pins every package in the resolved environment, including transitive dependencies, and is meant to be committed to version control. Reproducing the exact environment on another machine is then a single pixi install.

The prefix.dev blog covers this in more depth here.


Installing pixi

Run the following one-liner to install pixi on Linux or macOS:

curl -fsSL https://pixi.sh/install.sh | sh

After installation, restart your terminal or source your shell config to make the pixi command available:

# Linux (bash)
source ~/.bashrc

# macOS (zsh)
source ~/.zshrc

If the installation succeeded, typing pixi in the terminal should print pixi’s help message.


Setting up a project

Pixi is project-centric: dependencies are tracked per directory, not per named environment (though you can install packages globally). To initialize a new project:

pixi init my_project --channel conda-forge --channel bioconda
cd my_project

This creates a pixi.toml config file (analogous to environment.yml) and a hidden .pixi/ directory where the environment lives.

If you are already inside a directory you want to use:

pixi init . --channel conda-forge --channel bioconda

Now a pixi project is created and uses channels conda-forge and bioconda


Installing packages

Once inside your project directory, add packages with pixi add:

pixi add bioconda::samtools
pixi add bioconda::minimap2 bioconda::bedtools

Pixi resolves and installs quickly, and records the exact versions in pixi.lock for full reproducibility.


Running tools

Option 1: pixi run (no activation needed)

The simplest way to use a tool is to prefix it with pixi run. This works from within the project directory without activating anything:

pixi run samtools view -h input.bam
pixi run python my_script.py

Option 2: pixi shell (activate the environment)

If you prefer an interactive session where tools are available directly on your $PATH, use pixi shell. This is the pixi equivalent of conda activate:

# Enter the environment (similar to `conda activate`)
pixi shell

# Now you can run tools directly
samtools view -h input.bam
python my_script.py

# Leave the environment
exit

pixi run only works from within the project directory. After pixi shell, you can use tools anywhere, even outside the project directory—until you exit.


Global packages

For tools you want available everywhere regardless of project, pixi supports global installs:

pixi global install bioconda::samtools
pixi global install bioconda::minimap2

Some tools have conflicting dependencies. Pixi handles this by letting you group them into named global environments:

# Install two packages into a shared global environment called "biotools"
pixi global install --environment biotools bioconda::samtools bioconda::bedtools

This avoids conflicts while keeping tools globally accessible.


Project-based vs named environments

One of the most actively debated aspects of pixi is that environments are tied to directories rather than names. Conda users are accustomed to conda activate my_env working from anywhere on the system; pixi’s pixi shell only works from within the project directory (except global packages).

The current best workaround is the --manifest-path flag, which lets you activate any project’s environment from any working directory by pointing pixi at the pixi.toml:

pixi shell --manifest-path /path/to/my_project/pixi.toml

In recent versions of pixi, this activated environment persists across future pixi calls for the duration of that shell session, so you only need to specify the path once. The downside is obvious: it’s verbose, and you have to remember where the pixi.toml lives.

A common workaround shared on the prefix.dev Discord is a small shell function that mimics conda activate:

# Add to ~/.bashrc or ~/.zshrc
function pixi-activate() {
    local project_path="$1"
    pixi shell --manifest-path "${project_path}/pixi.toml"
}

Then you can do:

pixi-activate ~/projects/my_analysis

This is still more explicit than conda activate my_env, and it requires you to know the path rather than a memorable name—but it is workable for most workflows. Whether pixi will eventually support named, globally-registered environments remains an open question.


Cache directory

Conda stores downloaded package tarballs and extracted environments in ~/.conda/pkgs/ and ~/anaconda3/pkgs/ by default—both inside $HOME. On shared servers and HPC clusters where $HOME quotas are tight (often 10–50 GB), a growing conda installation can quietly fill up your home directory and cause cryptic failures. I have run into this more than once. The workaround with conda is to redirect the cache via .condarc:

# ~/.condarc
pkgs_dirs:
  - /path/to/larger/disk/conda_pkgs

Pixi uses a different location by default:

Platform Default cache path
Linux ~/.rattler/cache
macOS ~/Library/Caches/rattler/cache

On Linux, ~/.rattler/cache is still in $HOME, so the same quota concern applies on HPC systems. To relocate the pixi cache, set the RATTLER_CACHE_DIR environment variable:

# e.g., in ~/.bashrc or ~/.zshrc
export RATTLER_CACHE_DIR=/path/to/larger/disk/rattler_cache

Note that the .pixi/ directory inside each project folder contains the installed environment, not the cache. The cache holds the downloaded packages shared across all projects; the .pixi/ directory holds the hard-linked or extracted files for that specific project. You can safely delete .pixi/ and recreate it with pixi install—pixi will reuse cached packages and not re-download anything.


Using pixi on a job scheduler (SLURM)

pixi shell spawns an interactive subshell, so it does not work in SLURM batch scripts.

Make pixi available in SLURM

Slurm jobs don’t source ~/.bashrc by default. You need to expose Pixi’s executable to $PATH first.

export PATH="$HOME/.pixi/bin:$PATH"

Then there are two good alternatives to run pixi packages.

Prefix each command with pixi run from within the project directory:

#!/bin/bash
#SBATCH --job-name=my_job
#SBATCH --cpus-per-task=4
export PATH="$HOME/.pixi/bin:$PATH"
cd /path/to/project
pixi run samtools sort -@ 4 input.bam -o sorted.bam
pixi run python my_script.py

Option 2: pixi shell-hook

Use pixi shell-hook to emit the activation commands and eval them. This effectively activates the environment inside the script:

#!/bin/bash
#SBATCH --job-name=my_job
export PATH="$HOME/.pixi/bin:$PATH"
cd /path/to/project
eval "$(pixi shell-hook)"
# Tools are now on $PATH
samtools sort input.bam -o sorted.bam
minimap2 -ax sr ref.fa reads.fastq > aligned.sam

To activate a specific named environment (if your pixi.toml defines multiple):

eval "$(pixi shell-hook -e myenv)"

Is pixi a full replacement for conda?

For most bioinformatics use cases, Pixi installs from bioconda and conda-forge, so virtually any tool you used via conda is available. The project-based model takes some getting used to if you are accustomed to named global environments, but it tends to produce cleaner, more reproducible setups.

A few things to keep in mind:

  • No conda activate by name. Pixi environments are tied to directories, not names. If you work across many one-off analyses, you may want to adopt the habit of creating a project directory per analysis.
  • pixi shell is per-project. Unlike conda activate env_name which works from anywhere, pixi shell must be invoked from the project directory (though once activated, you can navigate freely).
  • Global installs are separate. Tools installed with pixi global install are distinct from project environments. Think of them as your “always available” utilities.

Overall, the faster dependency resolution, automatic lockfiles, and genuinely global installs make pixi a compelling upgrade for bioinformatics workflows.

AI tools were used in preparing background research for this post.