Skip to main content
v2026.11,772 entries · CC-BY 4.0

Conda, Pip, and Mamba in One Environment: Order Matters

Mixing pip installs into a conda or mamba environment is normal, but conda’s solver can’t see what pip did. Here is the safe order of operations and how to declare both in one environment.yml.

Written and maintained by CASRAI Editorial Board

Last updated

Almost every non-trivial scientific Python or bioinformatics environment ends up needing both a conda-style package (from conda-forge or Bioconda) and a package that only exists on PyPI. Mixing conda or mamba installs with pip installs in the same environment is normal and often unavoidable — but it is also one of the most common ways a working environment quietly turns into a broken one. The failure mode is not random: it follows directly from how conda’s solver works, and it is entirely avoidable once you understand the order of operations and how to declare both package sources correctly in a single environment.yml.

Why pip-installed packages are invisible to conda’s solver

Conda (and mamba, which uses the same environment model and reads the same environment.yml files) manages an environment by solving a dependency graph: given the packages you’ve asked for, it works out a mutually compatible set of versions across every package already in the environment, then records that resolution in its own package metadata. That metadata is conda’s, not the operating system’s or Python’s — it lives in conda-meta/ inside the environment and is what every subsequent conda install or conda update reads before deciding what to change.

Pip does not write to that metadata. When you run pip install inside an active conda environment, pip installs into that environment’s site-packages the same way it would into any Python environment, using its own dependency resolver and its own record of what’s installed (Python’s standard packaging metadata). Conda’s solver has no visibility into that. As conda’s own documentation puts it, conda “has limited abilities to control packages that it did not install” — from conda’s point of view, anything pip put there is opaque. conda list will show pip-installed packages (labelled with a pypi channel), but conda cannot verify their dependencies were satisfied the way it would for its own packages, and it will happily overwrite them without knowing what it’s breaking.

What actually breaks when you conda-install after pip

This asymmetry is why order matters. If you pip install a package and then later run conda install for something else, conda’s solver may decide to upgrade or downgrade a shared dependency to satisfy its own graph — a dependency that your pip-installed package needs at a specific version, but that conda doesn’t know is load-bearing for it. The official conda documentation is explicit about the risk: “running conda after pip has the potential to overwrite and potentially break packages installed via pip.” The reverse can also happen: pip, run after conda, can upgrade or remove a package that conda-installed software depends on, since pip’s resolver doesn’t consult conda’s metadata either.

In practice this shows up as import errors after an apparently unrelated install, a compiled extension suddenly pointing at the wrong shared library version, or a workflow manager failing mid-pipeline on a rule that worked yesterday. None of this is a bug in conda or pip individually — it’s the predictable result of two independent solvers managing the same site-packages directory with no shared source of truth, and it’s exactly the kind of hidden environment drift that undermines computational reproducibility when a captured environment turns out not to reinstall the way it did originally.

The recommended order of operations

The fix conda’s own documentation recommends is procedural, not a flag or a config setting: install as many requirements as possible with conda (or mamba) first, and use pip only for what conda-forge/Bioconda genuinely don’t provide, as the last step. Concretely:

  1. Create the environment and install every package that’s available via conda-forge or Bioconda first — this includes anything with compiled/binary dependencies (numerical libraries, aligners, anything linking against system BLAS/LAPACK, CUDA-dependent packages), where conda’s binary builds avoid the compiler toolchain and ABI issues pip/PyPI wheels can run into.
  2. Only then install the remaining PyPI-only packages with pip, inside that same activated environment.
  3. Leave pip’s default --upgrade-strategy only-if-needed alone (don’t pass --upgrade broadly), and avoid pip install --user inside a conda environment — it installs outside the environment’s own site-packages and defeats the isolation conda is providing.
  4. If you later need to add more conda packages to an environment that already has pip installs in it, treat that as a signal to recreate the environment from a spec file rather than layering another conda install on top. Once pip has modified the environment, conda’s solver is working from stale assumptions about what’s actually there, and the safest way to get a consistent environment back is to rebuild it in the correct order, not to keep patching it.

This same ordering logic holds whether you use conda or mamba as the solver — mamba is a faster, C++ reimplementation of conda’s core CLI (and since conda 23.10, its libmamba solving engine is conda’s own default too), but it manages the identical conda-meta/ metadata and has the identical blind spot toward anything pip installed. See Mamba vs Conda for how the two tools compare on solving speed specifically; the pip-interaction behavior described here is the same for both.

Declaring both conda and pip packages in one environment.yml

For a reproducible, shareable environment, don’t rely on remembering the right install order by hand — declare it once in environment.yml, which both conda and mamba read identically. Conda’s package-spec format supports a nested pip: list inside the top-level dependencies: list, which is installed via pip after every other listed conda dependency has been resolved and installed — the file itself encodes the correct order:

name: my-project
channels:
  - conda-forge
  - bioconda
dependencies:
  - python=3.11
  - numpy
  - pandas
  - samtools
  - pip
  - pip:
      - some-pypi-only-package==2.3.1
      - another-pip-package

Two details matter here. First, pip itself must be listed as a regular conda dependency (as shown above) so that a pip binary actually exists inside the environment for the nested list to use — without it, environment creation will fail trying to run the pip: section. Second, keep the split intentional: everything that has a conda-forge or Bioconda build belongs in the top-level dependencies: list, and the pip: block is reserved for packages that genuinely don’t have one. Treating pip: as a catch-all for anything you didn’t feel like looking up defeats the point — you lose conda’s binary compatibility guarantees for packages that didn’t need to be pip-only in the first place.

Build the environment from the file with either tool — conda env create -f environment.yml or the equivalent mamba env create -f environment.yml — and both will install the top-level conda dependencies first, then run pip against the nested list, in the order the file already encodes.

Checking and exporting a mixed environment

A few commands are worth knowing once an environment has both kinds of packages in it:

  • conda list shows every package in the environment, including pip-installed ones (marked with the pypi channel rather than conda-forge/bioconda), so you can see at a glance what came from where.
  • conda env export inspects the environment’s installed packaging metadata and will include a pip: section listing the pip-installed packages alongside the conda ones, so a single exported file captures both — useful for committing a working environment’s exact state to version control as part of a broader software management plan. Add --no-builds if you want the export to be more portable across platforms (dropping conda’s exact build-string pins while keeping version numbers).
  • pip check verifies that pip’s own view of installed-package dependencies is internally consistent — it won’t catch a conda-side conflict, but it’s a quick way to confirm pip’s installs at least satisfy each other’s stated requirements.

None of these substitute for getting the install order right in the first place; they’re diagnostic tools for confirming (or debugging) an environment after the fact, not a way to safely mix installs in arbitrary order. A pinned, version-controlled environment.yml alongside a tool like DVC for the data and outputs it produces is the more durable pattern — and it’s the kind of environment provenance a research software engineer or informatics-support team will expect to see before they can debug or rebuild a pipeline that isn’t theirs.

Frequently asked questions

Can I install pip packages before conda packages, if I’m careful?

Technically the environment won’t refuse it, but it inverts the safety the ordering is designed to provide: any conda package you install afterward can silently override something pip already put in place, since conda’s solver still won’t check pip’s installs before deciding what to change. There’s no equivalent safe way to do it in reverse — conda-first, pip-last is the only ordering where each tool’s install pass is aware of what came before it.

Does mamba handle the pip interaction any differently than conda?

No. Mamba is a reimplementation of conda’s CLI and solver engine, but it operates on the same environment and the same conda-meta/ metadata conda does, so it has the identical blind spot toward pip-installed packages. Everything above applies equally whether you run conda install/conda env create or the mamba equivalents.

My environment is already broken from conda and pip stepping on each other — how do I fix it?

Rebuild it rather than trying to reconcile it in place. Write (or fix) an environment.yml with the conda-forge/Bioconda-available packages in the top-level dependencies: list and the PyPI-only ones in the nested pip: list, then create a fresh environment from that file. Patching a mixed environment that’s already inconsistent tends to compound the problem rather than resolve it, since each subsequent install is still working from an incomplete picture.

If a package is available on both conda-forge and PyPI, which should I use?

Prefer the conda-forge/Bioconda build when one exists, particularly for anything with compiled or binary dependencies (numerical/scientific libraries, aligners and other bioinformatics binaries). Conda’s binary packaging manages the underlying compiled libraries and their compatibility as part of the same dependency graph; installing the equivalent PyPI wheel bypasses that and is exactly the kind of package that later triggers a conda/pip conflict. Reserve pip for packages that are genuinely PyPI-only — it keeps the environment closer to the kind of reusable, well-specified software a FAIR software checklist expects, rather than a pile of ad hoc pip installs nobody can reconstruct.

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Ask CASRAI · included with Regulatory Radar

Ask about Conda, Pip, and Mamba in One Environment: Order Matters

Ask CASRAI answers research-administration questions and cites the passages behind every claim — and says so when the corpus does not cover something, instead of guessing. It comes with a Regulatory Radar subscription at $29 a month, alongside the daily digest of regulatory changes and the dashboard of what changed.

150 questions a day, on this site, over the API, or inside your own tools through the CASRAI MCP server.

Everything CASRAI publishes — this page, the dictionary, the guides and the news — stays free to read, with no account and no card.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →

Regulatory Radar

Stop finding out after the fact

$29/month, cancel anytime. Daily digest updates from our analysis, a dashboard holding the same items, and a cited assistant for everything they raise.

  • Federal Register, Federal Register+, Grants.gov, Regulations.gov, NSF News, UKRI, plus CASRAI’s own published content.
  • 72,264 indexed passages, and every answer cites the ones it drew on.