# conda-pypi


conda-pypi is a [conda](https://pydevtools.com/handbook/reference/conda.md) plugin that installs [PyPI](https://pydevtools.com/handbook/explanation/what-is-pypi.md) packages into a conda environment by converting their sdists or [wheels](https://pydevtools.com/handbook/reference/wheel.md) into the [`.conda` format](https://pydevtools.com/handbook/reference/conda-package.md) at install time. The conda solver tracks every package the plugin installs, which closes the long-standing gap where [pip](https://pydevtools.com/handbook/reference/pip.md)-installed packages were invisible to conda and the two views of the environment would drift apart. As of conda 26.5.3, the conda-pypi channel integrates with the standard `conda install` command, enabling a single solve across conda-forge and PyPI packages without a separate pip step.

> [!WARNING]
> conda-pypi is in public beta (June 2026). The plugin is suitable for experimentation and non-critical workloads, but the Conda team does not yet recommend it for production environments.

## Why conda-pypi Exists

Mixing conda and pip in a single environment is a recurring source of broken installs. Conda's dependency solver only sees packages it installed; pip's only sees packages it installed. When the two install overlapping dependencies, conda can overwrite pip-installed files, pip can leave conda's metadata stale, and `conda update` afterward can produce an environment that no longer matches either tool's record of it. The conventional workaround is the pip-last pattern: install everything available on conda channels first, run `pip install` for whatever is left, and never run a conda command in that environment again. The pattern works but is fragile and undocumented in the environment itself.

conda-pypi replaces the pattern with a single tool that records PyPI installs the same way conda records its own. Every PyPI package becomes a `.conda` artifact with its metadata indexed in the environment, so the solver sees it on subsequent operations. The plugin also installs an `EXTERNALLY-MANAGED` marker (the [PEP 668](https://pydevtools.com/handbook/explanation/what-is-pep-668.md) mechanism that Debian uses to protect the system Python) so accidental `pip install` invocations are refused with a message pointing at `conda pypi install` instead.

## Installation

conda-pypi requires conda 26.5.3 or newer and the rattler solver. On a recent [Miniforge](https://github.com/conda-forge/miniforge), one command pulls in both:

```bash
conda install -n base "conda>=26.5.3"
```

The upgrade transaction pulls `conda-pypi` and `conda-rattler-solver` in as dependencies. After the upgrade, configure the rattler solver and the conda-pypi channel:

```bash
conda config --set solver rattler
conda config --append channels conda-pypi
```

`conda --version` should report `26.5.3` or newer when the upgrade completes. No shell restart is required.

## The conda-pypi Channel

The `conda-pypi` channel hosted by Anaconda publishes metadata for approximately 600,000 pure Python wheels pre-validated against conda packaging conventions. The wheel files themselves are still fetched from `pypi.org` at install time. The channel is free for all use and is not subject to the Anaconda commercial-license terms that apply to the default channel.

Appending the channel globally (the `conda config --append channels conda-pypi` step in [Installation](#installation)) enables the native `conda install` integration. This is the recommended configuration as of conda 26.5.3.

## Usage

### Native `conda install`

With the `conda-pypi` channel appended to the global config (see [Installation](#installation)), the standard `conda install` command resolves conda-forge and PyPI packages together:

```bash
conda install scipy requests
```

`scipy` resolves from conda-forge; `requests`, if not available on any conda channel, resolves from PyPI and is converted to a `.conda` artifact before being installed. Packages from both sources are tracked in conda-meta on equal footing.

Multi-platform lockfiles work the same way:

```bash
conda list --explicit --from-history > environment.lock
```

Pass `--platform linux-64`, `--platform osx-arm64`, etc. to generate platform-specific lockfiles.

## Subcommands

### `conda pypi install`

Installs PyPI packages into the active or named environment using a hybrid resolution strategy. Explicitly requested packages always come from PyPI and are converted to `.conda` format on the fly. Dependencies follow a conda-first preference: if a dependency exists on a configured conda channel, conda installs that build; otherwise the dependency is also pulled from PyPI and converted.

Use this subcommand when you need flags specific to PyPI installs (editable installs, custom index URLs) that the standard `conda install` command does not expose.

Common flags:

- `-n, --name ENV` (parent flag on `conda pypi`) targets a named environment without activating it.
- `-p, --prefix PATH` targets an environment by full path.
- `-i, --index-url URL` adds a PyPI index URL; can be repeated for multiple indexes.
- `--ignore-channels` forces every package, including dependencies, to be resolved from PyPI rather than the configured conda channels.
- `-e, --editable PATH` installs a local project in editable mode by building a `.conda` artifact from the source tree and linking it into the environment.
- `-d, --dry-run` (parent flag on `conda pypi`) reports the resolved install plan without writing files. Invoked as `conda pypi -d install <pkg>`.

Package names are translated between PyPI and conda conventions using the [Grayskull](https://github.com/conda/grayskull) name-mapping tables.

### `conda pypi convert`

Builds a local Python project, sdist, or wheel into a `.conda` artifact without installing it. Useful for preparing offline installs, building internal mirrors, or inspecting how the plugin would translate a package before committing to an install.

The positional argument is a path on the local filesystem, not a PyPI package name. Convert a remote package by downloading the wheel first (for example with `pip download`) and pointing `conda pypi convert` at the local file.

Common flags:

- `--output-folder DIR` writes the converted artifacts to a directory rather than the conda package cache.
- `-e, --editable` builds the project as an editable package.
- `-t, --test-dir DIR` injects a test-files directory into the converted conda package.
- `--name-mapping FILE` points at a JSON file containing a custom PyPI-to-conda name mapping.

## Environment Protection

When conda-pypi is installed into an environment, the plugin places an `EXTERNALLY-MANAGED` file in the environment's standard library location. Subsequent `pip install` calls against that environment fail with the [PEP 668](https://pydevtools.com/handbook/explanation/what-is-pep-668.md) rejection message, which conda-pypi customizes to direct users to `conda pypi install` instead. See [How to fix the externally-managed-environment error](https://pydevtools.com/handbook/how-to/how-to-fix-the-externally-managed-environment-error.md) for the underlying mechanism.

The warning can be disabled per environment with `conda config --set plugins.conda_pypi_pip_warning false`, though doing so reintroduces the failure mode the plugin is designed to prevent.

## Limits

- **Pure Python wheels only.** Packages with platform-specific compiled extensions are not supported. Compiled scientific stacks (NumPy, SciPy, PyTorch, CuPy) must come from conda-forge or another conda channel.
- **[PEP 508](https://peps.python.org/pep-0508/) dependency markers are partially handled.** The `extra == "..."` form is split into per-extra dependency tables in the converted `.conda` artifact. Other environment markers (`python_version`, `sys_platform`, `os_name`) are dropped during conversion, which can produce a thinner dependency graph than the wheel itself would install via pip.
- **The wheel-channels feature is experimental.** A draft [Conda Enhancement Proposal](https://github.com/conda/ceps) defines how a channel can expose wheels directly in its repodata under a `v3.whl` section. The conda-pypi plugin implements this path, but the specification is still under discussion and the on-disk format is not guaranteed to remain stable.
- **Security inherits PyPI's model.** The channel only republishes metadata; the wheel files themselves come from `pypi.org` without independent vetting. Supply-chain controls that apply to PyPI (trusted publishing, attestations, package signing) also apply here. Conda-forge's screened feedstock process does not.

## Related Approaches

- **[pixi](https://pydevtools.com/handbook/reference/pixi.md)** resolves conda-forge and PyPI packages together in a single lockfile, using uv internally for the PyPI side. The model is integrated from the start rather than bolted onto conda after the fact; pixi is the alternative to evaluate when both PyPI and compiled-wheel interop matter and a project-local workflow is acceptable. See [uv vs pixi vs conda for scientific Python](https://pydevtools.com/handbook/explanation/uv-vs-pixi-vs-conda-for-scientific-python.md).
- **The pip-last convention** is the long-standing workaround that conda-pypi replaces. Install every available dependency via conda first, run `pip install` once for the remainder, and avoid further conda operations in the environment. It still works and is appropriate for teams that cannot adopt beta tooling, but it leaves no record in the environment that pip was used.

## Pros

- Standard `conda install` resolves conda-forge and PyPI packages in one operation; no pip step, no separate tool.
- The conda solver tracks PyPI packages on the same footing as conda packages, eliminating the silent-drift failure mode of mixed environments.
- Hybrid resolution prefers conda-channel builds for dependencies, which keeps compiled libraries on a tested build path even when the requested package is PyPI-only.
- `EXTERNALLY-MANAGED` enforcement prevents accidental `pip install` from corrupting environments after the fact.
- Editable installs work the same way as `pip install -e`, supporting standard development workflows.
- The conda-pypi channel covers approximately 600,000 pure Python wheels and is free for all use without Anaconda commercial-license obligations.

## Cons

- Beta software; not recommended for production by its maintainers.
- Pure Python wheels only; compiled extensions require conda-forge or another conda channel.
- Requires conda 26.5.3 plus the rattler solver, which is newer than many existing installations.
- [PEP 508](https://peps.python.org/pep-0508/) environment markers other than `extra ==` are dropped during conversion.
- The wheel-channels feature depends on a CEP still under discussion.

## Learn More

### Handbook pages

- [conda](https://pydevtools.com/handbook/reference/conda.md)
- [conda-forge](https://pydevtools.com/handbook/reference/conda-forge.md)
- [conda package](https://pydevtools.com/handbook/reference/conda-package.md)
- [pixi](https://pydevtools.com/handbook/reference/pixi.md)
- [Understanding the Conda/Anaconda Ecosystem](https://pydevtools.com/handbook/explanation/understanding-the-conda-anaconda-ecosystem.md)
- [uv vs pixi vs conda for scientific Python](https://pydevtools.com/handbook/explanation/uv-vs-pixi-vs-conda-for-scientific-python.md)
- [How to fix the externally-managed-environment error](https://pydevtools.com/handbook/how-to/how-to-fix-the-externally-managed-environment-error.md)

### Official documentation

- [conda-pypi documentation](https://conda.github.io/conda-pypi/)
- [Quickstart](https://conda.github.io/conda-pypi/quickstart/)
- [Features](https://conda.github.io/conda-pypi/features/)
- [GitHub repository](https://github.com/conda-incubator/conda-pypi)
- [Conda Enhancement Proposals](https://github.com/conda/ceps)
