I'm Transitioning from Conda to Pixi
Warning: I’m not really making a point here, I’m mostly just venting.
The Problem
Surely this must be a common problem among computational mathematicians. You teach a class with a computational component, and you want to distribute code to your students. The average student in these classes at best has exposure to MATLAB, or maybe Mathematica. But, the reality is that an increasing majority of mathematical research is being done in Python, not to mention that it’s obviously massively applicable to industry. I like my students. I want them to succeed. I want them to learn and use Python.
Naively, I write some nice Python code. Clean, readable, beautiful visualizations. I hand them the files. With wonder, curiosity, and hope, they say “Cool! How do I run this?”.
Isn’t it insane that I have to snuff out the life in eyes on step one?
Okay, I could use something like Google Colab. I suppose I understand why so many people in my field are comfortable with notebooks, what with that being the easiest way to run a simple script. Otherwise, I’m staring down the barrel of explaining 1) how to get Python on your system to begin with and why that shouldn’t be something like your system’s package manager, 2) why, for our scientific computing ecosystem, we have to use packages off of conda-forge instead of PyPI (mostly), and 3) conda itself. Each of those are uncomfortable conversations when I’m trying to convince them to use a different tool (MATLAB is a 1-click install). Compounding the problem, sometimes I have to begin with explaining what a terminal is.
Well, Pixi doesn’t exactly fix this. I should just wrap up this post give them notebooks. But, I hate the overreliance of our space on notebooks. They’re great for exploration, or tutorials. But, their format inherently encourages bad programming practices and students, who haven’t seen anything else, end up writing monster notebooks. I debugged multiple such specimens during my PhD years, trying to strip out the critical pieces for my own research. I want them to see better ways to do things.
Pixi
Pixi is a new(-ish) package manager that operates off of conda-forge. That’s critical for scientific computing, given how many dependencies in our field are enormous C/C++/Fortran libraries. PyPI is great for Python packages, but it explicitly isn’t designed for such projects. Otherwise, I would happily be using uv.
Why not just use Conda? I actually don’t have big problems with it, especially after mamba mostly solved the performance issues. However, it’s far from a seamless experience; there’s a lot of intermediate steps and manual intervention required to set up a new enviornment. Not to mention it drapes itself all over your system and paths, which causes problems for other tools. For example, Firedrake, an excellent finite element library, specifically calls out conda as an anti-requirement. Furthermore, most people I know just ad-hoc install packages into enviornments. More often than note, I find existing env.yml
to be outdated, or just plain wrong.
In contrast, Pixi is faster, doesn’t pull any path shenanigans (it’s just a binary), and is specifically designed to integrate into workspaces. If I want to pass some code to students, I toss them repository with the files, a pixi.toml
+ pixi.lock
, and a README with a command or two.
Recently, I took steps to completely clean my system of Conda (unsurprisingly annoying, but therapeutic), and now I’m using Pixi exclusively for my research. I’m happy to say, atleast in PDE (FEniCS) and neural network land (PyTorch \& JAX), it has been a mostly smooth transition. It was somewhat uncomfortable to transition to thinking about projects, as opposed to global enviornments. I realized I had developed a bad habit of creating “mega-enviornments”, with a bunch of frequently used packages, that I just carted around to different projects. I suppose bad-habits like that are things that Pixi should fix, though I admit that spinning up a whole new workspace for tiny little Python scripts seems a bit overkill. I should look into uv
’s ability to, on-demand, load dependencies for this setting. For example, from their website
# /// script
# dependencies = [
# "requests<3",
# "rich",
# ]
# ///
import requests
from rich.pretty import pprint
resp = requests.get("https://peps.python.org/api/peps.json")
data = resp.json()
pprint([(k, v["title"]) for k, v in data.items()][:10])
This script can just be run, with dependencies resolved on-demand, by
❯ time uv run example.py
Installed 9 packages in 27ms
[
│ ('1', 'PEP Purpose and Guidelines'),
│ ('2', 'Procedure for Adding New Modules'),
│ ('3', 'Guidelines for Handling Bug Reports'),
│ ('4', 'Deprecation of Standard Modules'),
│ ('5', 'Guidelines for Language Evolution'),
│ ('6', 'Bug Fix Releases'),
│ ('7', 'Style Guide for C Code'),
│ ('8', 'Style Guide for Python Code'),
│ ('9', 'Sample Plaintext PEP Template'),
│ ('10', 'Voting Guidelines')
]
uv run example.py 0.50s user 0.15s system 76% cpu 0.851 total
I’m trained by the previous python ecosystem to think that this would incur unbearable latency. But 27ms is basically the same time as a requests call, this is fantastic work. The new age of Python developer tools (seemingly all written in Rust) is wonderful to work with. From the Pixi folk, I’m also very much looking forward to the completion of rattler-build, so that it’s easier to push packages to conda-forge as well.
Enjoy Reading This Article?
Here are some more articles you might like to read next: