Move from Conda to Mamba
Table of Contents
- Migrating from Anaconda/Miniconda (conda) to Miniforge (mamba)
- 1. List the conda environments
- 2. Download the Python script to fix exported YAML
- 3. Create mamba compatible exported YAML files
- 4. Uninstall conda (Anaconda/Miniconda)
- 5. Install mamba (Miniforge)
- 6. Clear cache
- 7. Enforce strict channel policy
- 8. Verify channel configuration
- 9. Rebuild old env with mamba
- Appendix A:
fix_yaml.py
Migrating from Anaconda/Miniconda (conda) to Miniforge (mamba)
This guide migrates your environments away from Anaconda/Miniconda (conda) to Miniforge (mamba), using conda-forge only (non-commercial) and avoiding anaconda.org
/repo.anaconda.com
.
Steps 1–3 use your existing conda
to export environments. After uninstall (Step 4) you’ll install Miniforge (Step 5) and rebuild environments with mamba (Step 9).
1. List the conda environments
Use your current conda to list environments before migrating.
conda env list
# or (equivalent)
conda info --envs
2. Download the Python script to fix exported YAML
This script: - removes duplicate packages, - drops prefix:
and other install-specific metadata, - forces conda-forge, bioconda and defaults as the only channels, - prepares the file for mamba environment creation.
Copy the script from Appendix A into fix_yaml.py
.
3. Create mamba compatible exported YAML files
Export a single environment named xyz
:
conda env export --name xyz | python3 fix_yaml.py - -o xyz.yml
You can export all environments at once:
for env in $(conda env list | grep -v "^#" | awk 'NF>1 {print $1}'); do
conda env export --name "$env" | python3 fix_yaml.py - -o "${env}.yml"
done
If you have path-only environments (created from arbitrary folders), conda env list
may show full paths instead of simple names. Consider exporting those individually to ensure correct name:
in the YAML.
4. Uninstall conda (Anaconda/Miniconda)
Follow vendor instructions (macOS/Linux):
https://www.anaconda.com/docs/getting-started/anaconda/uninstall#macos-or-linux
Then remove common leftovers:
# If Miniconda
rm -rf ~/miniconda ~/miniconda3
# If Anaconda
rm -rf ~/anaconda ~/anaconda3
rm -rf ~/.conda
rm -rf ~/.condarc
rm -rf ~/.continuum
rm -rf ~/.conda_envs_dir
rm -rf ~/.conda_envs_dir_test
Edit your shell init and delete the conda init
block:
# >>> conda initialize >>>
...
# <<< conda initialize <<<
Files to check (depending on your shell): ~/.zshrc
, ~/.bashrc
, ~/.bash_profile
.
Restart your terminal.
Make sure conda
is no longer on your PATH
:
which conda || echo "conda not found (expected)"
5. Install mamba (Miniforge)
Download mamba for macOS:
# Apple Silicon (M1/M2/M3):
curl -L -O https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge-MacOSX-arm64.sh
# Intel Macs:
curl -L -O https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge-MacOSX-x86_64.sh
# Install (interactive)
bash Miniforge-MacOSX-*.sh
Verify:
mamba --version
mamba info | sed -n '1,60p'
Once mamba installation is completed then delete the install script.
rm -f Miniforge-MacOSX-*.sh
6. Clear cache
# Safe to run; ignores errors if conda is gone
conda clean --all -y || true
mamba clean --all -y || true
7. Enforce strict channel policy
# Start fresh (ignore error if key doesn't exist)
mamba config remove-key channels 2>/dev/null || true
# Add exactly the three you want
mamba config prepend channels conda-forge
mamba config append channels bioconda
mamba config append channels defaults
# Recommended
mamba config set channel_priority strict
This: - forces to be conda-forge, bioconda and defaults in that order - removes any other channels that may point to anaconda.com
8. Verify channel configuration
# High-level info (shows channel list)
mamba info
# Full config dump
mamba config list | sed -n '1,200p'
What you want to see: - channels
shows only conda-forge
, bioconda
, and defaults
- Nothing should reference repo.anaconda.com
or anaconda.org
.
9. Rebuild old env with mamba
Recreate from your cleaned YAMLs:
# Single env
mamba create -f xyz.yml --yes --override-channels
# All YAMLs in current directory
for y in *.yml *.yaml 2>/dev/null; do
[ -f "$y" ] || continue
echo "Rebuilding from $y"
mamba create -f "$y" --yes --override-channels
done
During solve, you should NOT see:
warning libmamba 'repo.anaconda.com', a commercial channel hosted by Anaconda.com, is used.
If you do, revisit Steps 7–8 to correct your channel configuration.
Activate and test:
mamba activate xyz
python -V
Appendix A: fix_yaml.py
This script reads an exported conda env export
YAML from stdin (or a file), removes duplicates, deletes prefix:
, forces appropriate channels, removes unwanted channels, preserves pip:
sections, and writes the cleaned YAML to stdout (or -o FILE
).
#!/usr/bin/env python3
"""
fix_yaml.py
- Normalize an exported conda environment YAML for mamba recreation.
- Drops install-specific fields (prefix), forces conda-forge channels, de-duplicates dependencies.
Usage:
python3 fix_yaml.py input.yml -o output.yml
conda env export --name myenv | python3 fix_yaml.py - -o myenv.yml
"""
import sys
import argparse
import io
from collections import OrderedDict
try:
import yaml # PyYAML if available
except Exception:
= None
yaml
def load_text(stream):
return stream.read()
def parse_yaml(text):
if yaml is None:
# Minimal fallback: very light parser for a subset of env YAML
# It preserves lines and does line-level dedup under `dependencies:`.
# For robust parsing, install PyYAML: mamba install pyyaml
= {"_raw": text}
data return data
return yaml.safe_load(text)
def dump_yaml(data):
if yaml is None:
# Fallback: return original text with only simple text transforms
= data["_raw"].splitlines(True)
lines
= [], False, set(), False
out, in_deps, seen, skip_prefix for ln in lines:
if ln.startswith("name:"):
out.append(ln)continue
if ln.strip().startswith("prefix:"):
# drop
continue
if ln.strip().startswith("channels:"):
"channels:\n - conda-forge\n - bioconda\n - defaults\n")
out.append(= True
skip_prefix continue
if skip_prefix:
# skip original channel lines until a non-channel item appears
if ln.startswith(" ") or ln.startswith("\t") or ln.strip().startswith("-"):
# still channel block; skip
continue
else:
= False
skip_prefix
if ln.strip() == "dependencies:":
= True
in_deps
out.append(ln)continue
if in_deps:
# New rule: handle lines with two '='
if ln.count("=") >= 2:
= ln.find("=")
first = ln.find("=", first + 1)
second if second == first + 1:
out.append(ln)continue
else:
# case like 'pkg=1=py39_0' → keep only before 2nd '='
= ln.split("=")
parts = "=".join(parts[:2]) + "\n"
newln
out.append(newln)continue
else:
out.append(ln)if ln[0] != " " and ln.strip()[-1] == ":":
= False
in_deps continue
return "".join(out)
# PyYAML path (preferred)
if data is None:
= {}
data "prefix", None)
data.pop(
# Normalize channels → conda-forge only
"channels"] = ["conda-forge"]
data[
# De-duplicate top-level conda dependencies
= data.get("dependencies", [])
deps = []
new_deps = set()
seen
for item in deps:
if isinstance(item, str):
if item not in seen:
new_deps.append(item)
seen.add(item)elif isinstance(item, dict) and "pip" in item:
# Keep pip sublist as-is (with de-dup inside)
= item.get("pip", [])
pip_list = set()
pip_seen = []
new_pip for p in pip_list:
if p not in pip_seen:
new_pip.append(p)
pip_seen.add(p)"pip": new_pip})
new_deps.append({else:
# Unknown structured entry; keep
new_deps.append(item)
"dependencies"] = new_deps
data[
# Emit YAML
class OrderedDumper(yaml.SafeDumper):
pass
def _dict_representer(dumper, data):
return dumper.represent_dict(data.items())
OrderedDumper.add_representer(OrderedDict, _dict_representer)
return yaml.dump(data, Dumper=OrderedDumper, sort_keys=False)
def main():
= argparse.ArgumentParser()
ap "input", help="Input YAML file or '-' for stdin")
ap.add_argument("-o", "--output", help="Output YAML file (default: stdout)")
ap.add_argument(= ap.parse_args()
args
if args.input == "-":
= load_text(sys.stdin)
text else:
with open(args.input, "r", encoding="utf-8") as f:
= f.read()
text
= parse_yaml(text)
data = dump_yaml(data)
out
if args.output:
with open(args.output, "w", encoding="utf-8") as f:
f.write(out)else:
sys.stdout.write(out)
if __name__ == "__main__":
main()
That’s it! You’ve exported your old conda
environments, removed Anaconda/Miniconda, installed Miniforge, enforced conda-forge only, and rebuilt your environments with mamba—without touching anaconda.org
.