| name | conda-reproducible |
| description | Use when creating or editing `environment.yml`, diagnosing conda/mamba dependency conflicts, pinning dependencies, separating runtime vs dev environments, exporting lockfiles, or reproducing a broken environment on a new machine. Also use when the user mentions "conda env", "mamba env", "channels", "solver", or "spec conflict". |
Conda / mamba environments that survive contact with reality
Two-file convention
Every project keeps two environment files:
environment.yml — human-readable spec, loose-but-sane version ranges,
checked into git. This is what you edit.
environment.lock.yml — machine-generated lockfile, exact versions for
current platform. Regenerated by the user, checked into git for
reproducibility. Do not edit by hand.
Why two? The spec tells the solver what you want; the lockfile tells you
exactly what you got. Without the lockfile, "the same env" varies by the
month conda solves it.
Canonical environment.yml
name: toolname
channels:
- conda-forge
- bioconda
- nodefaults
dependencies:
- python=3.11
- samtools=1.19
- biopython=1.83
- numpy>=1.26,<2.0
- pandas>=2.1,<3.0
- pip
- pip:
- git+https://github.com/kavonrtep/other-tool@v0.4.1
Rules:
- Channel order matters.
conda-forge before bioconda unless you need
the opposite for a specific package. Inconsistent channel order across
envs causes "why does it break on machine X" mysteries.
nodefaults — the "defaults" channel pulls in Anaconda-curated builds
that often conflict with conda-forge. Disable it unless you have a reason.
- pip dependencies stay in the
pip: section so the solver sees them.
environment-dev.yml
name: toolname-dev
channels: [conda-forge, bioconda, nodefaults]
dependencies:
- pip
- pip:
- -e .[dev]
- pytest>=8
- pytest-cov
- ruff
- ipython
Generating the lockfile
mamba env create -f environment.yml -n toolname
mamba env export -n toolname --from-history > /dev/null
mamba env export -n toolname | grep -v "^prefix: " > environment.lock.yml
--from-history shows only user-requested packages; the lockfile is the
full solved set including transitive deps. We commit the full set.
Reproducing on a new machine
mamba env create -f environment.lock.yml
If this fails on a new platform (ARM vs x86, different OS), fall back to
environment.yml and generate a new lockfile for that platform as
environment.lock.<platform>.yml.
Resolving conflicts
When mamba create says "found conflicts":
- Try
mamba — it has a better solver than old conda. If you're already
on mamba, move on.
- Read the error for the first package pair in conflict; later ones are
usually cascades.
- Relax the pin on the older package. Most conflicts are from over-pinning
a leaf dep.
- If that fails: add
--strict-channel-priority. This often fixes
conda-forge vs bioconda tangles.
- Last resort: split into two envs joined by a script that activates each.
Lockfile-less alternatives
If the project uses pixi or conda-lock instead:
pixi.toml + pixi.lock — modern, cross-platform, single tool. Preferred
for new projects.
conda-lock lock -f environment.yml -p linux-64 — multi-platform
lockfiles with one command.
.claude/project.yml declares which tool this project uses.
The update ritual
Every time you touch environment.yml:
$EDITOR environment.yml
mamba env remove -n toolname
mamba env create -f environment.yml -n toolname
mamba env export -n toolname | grep -v "^prefix: " > environment.lock.yml
mamba activate toolname && pytest
git add environment.yml environment.lock.yml
git commit -m "Update deps: <what changed>"
Skipping any step is a bug that will surface as "works on my machine".
What not to do
conda install foo and expect environment.yml to pick it up. It doesn't.
- Pin every single dep to an exact version — the solver becomes miserable.
Pin what matters; let the rest float within a range.
- Ship
environment.yml without a lockfile and tell users "just conda create".
- Put
pytest / ruff in the runtime env — bloats the container.