conda-express (cx)
A single-binary bootstrapper for conda, powered by rattler. The cx binary is short for conda express.
conda-express is the distribution project for the cx and cxz binaries. It
is not an official conda distribution.
cx offers an alternative to the Anaconda Distribution, Miniconda, and Miniforge constructor-style installer pattern: a 7-11 MB native binary that bootstraps a managed conda base environment from a locked package set.
Quick start
# The first conda command bootstraps the managed prefix
cx info
# Run conda commands through cx
cx create -n myenv python=3.12 numpy pandas
cx create -n science python=3.12 scipy
# Activate environments using conda-spawn, without conda init
cx spawn myenv
On first use, cx automatically installs conda and its plugins into ~/.conda/express from
the built-in runtime lock. Subsequent invocations hand off to the installed
conda binary.
What gets installed
cx installs a managed conda stack from conda-forge:
| Package | Role |
|---|---|
| python >= 3.12 | Runtime |
| conda | Package manager |
| conda-rattler-solver | Rust-based solver without libmamba's native dependency chain |
| conda-spawn >= 0.1.0 | Subprocess-based environment activation |
| conda-completion >= 0.3.0 | Shell completion support |
| conda-exec >= 0.3.0 | Ephemeral package execution and PEP 723 script workflows |
| conda-pypi | PyPI interoperability |
| conda-self | Base environment self-management |
| conda-global | Global tool installation and PATH management |
| conda-workspaces >= 0.7.0 | Multi-environment workspace and task management |
See the included plugins reference for the commands and workflows these packages add.
Shell completion is available through the included conda-completion plugin:
cx completion status
cx completion install --dry-run --command-name cx
Pass --command-name cx when installing or generating a completion hook so it
registers cx instead of the underlying conda executable.
Ad hoc package commands can run through the included conda-exec plugin
without adding tools to the managed base prefix:
cx exec ruff --version
The conda-libmamba-solver and its 27 exclusive native dependencies (libsolv, libarchive, libcurl, spdlog, etc.) are excluded by default because cx configures conda-rattler-solver.
Versioning
conda-express versions follow the conda version in the runtime lock. If conda-express needs a packaging-only rebuild without changing the bundled conda version, it uses a post-release version.
Installation
Homebrew (recommended)
Homebrew is the recommended install path on macOS and Linux:
brew tap jezdez/conda-express https://github.com/jezdez/conda-express
brew install jezdez/conda-express/cx
Update later with brew upgrade cx.
Shell script
macOS / Linux:
curl -fsSL https://jezdez.github.io/conda-express/get-cx.sh | sh
Windows (PowerShell):
powershell -ExecutionPolicy ByPass -c "irm https://jezdez.github.io/conda-express/get-cx.ps1 | iex"
The script detects your platform, downloads the right binary, verifies the checksum, updates your shell profile / PATH, and runs cx info to bootstrap the managed prefix. Customize with environment variables:
CX_INSTALL_DIR— where to place the binary (default:~/.local/binor%USERPROFILE%\.local\bin)CX_VERSION— specific version to install without avprefix (default:latest)CX_NO_PATH_UPDATE— set to skip shell profile / PATH modificationCX_NO_BOOTSTRAP— set to skip the installer's eager bootstrap commandCX_SKIP_VERIFY— set to skip checksum verificationCX_PREFIX— managed prefix used by automatic bootstrap (default:~/.conda/express)CX_BUNDLE— bundle directory used during automatic bootstrapCX_OFFLINE— set to a truthy value to force offline bootstrap
GitHub Actions
Use the setup action from a pinned conda-express release tag:
steps:
- uses: jezdez/conda-express/.github/actions/setup-cx@<release-tag>
- run: cx info
The action downloads the matching cx release asset, verifies its checksum,
adds cx to PATH, and runs cx info by default. That first conda command
automatically bootstraps the managed prefix. Artifact Attestation
verification is available with verify-attestation: true.
See the GitHub Actions guide for automatic bootstrap, deferred bootstrap, and attestation examples.
From GitHub Releases
Download the binary for your platform from the latest release:
| Platform | File |
|---|---|
| Linux x86_64 | cx-x86_64-unknown-linux-gnu |
| Linux ARM64 | cx-aarch64-unknown-linux-gnu |
| macOS x86_64 (Intel) | cx-x86_64-apple-darwin |
| macOS ARM64 (Apple Silicon) | cx-aarch64-apple-darwin |
| Windows x86_64 | cx-x86_64-pc-windows-msvc.exe |
Windows ARM64 is not published for conda-express yet. conda-ship publishes Windows ARM64 builder assets, but full runtime bootstrap support is still gated by the conda package ecosystem.
Each file has matching .sha256, .info.json, .packages.txt, and
.runtime.lock files. Release artifacts are also covered by GitHub Artifact
Attestations:
gh attestation verify ./cx-x86_64-unknown-linux-gnu \
-R jezdez/conda-express \
--signer-workflow jezdez/conda-express/.github/workflows/release.yml
See the artifact verification guide for checksum, metadata, runtime lock, and air-gapped transfer checks.
Docker
A multi-arch image is published to GHCR on every release:
docker run --rm -v cx-data:/home/nonroot/.conda/express ghcr.io/jezdez/conda-express info
The image runs as non-root (uid 65532), can run with a read-only root filesystem when the managed prefix is mounted as a writable volume, and includes provenance attestations and SBOMs. Docker Desktop on macOS and Windows automatically selects the right architecture (linux/amd64 or linux/arm64).
docker run --rm --read-only --tmpfs /tmp \
-v cx-data:/home/nonroot/.conda/express \
ghcr.io/jezdez/conda-express info
# Run a conda command through cx
docker run --rm -v cx-data:/home/nonroot/.conda/express ghcr.io/jezdez/conda-express create -n myenv python=3.12
Use as a container in CI (GitHub Actions):
jobs:
test:
container: ghcr.io/jezdez/conda-express:latest
steps:
- run: cx create -n test python numpy
Use as a base for multi-stage application builds:
FROM ghcr.io/jezdez/conda-express:latest AS conda-builder
RUN cx create -n app python numpy pandas
FROM gcr.io/distroless/cc-debian12:nonroot
COPY --from=conda-builder /home/nonroot/.conda/express/envs/app /opt/conda
PyPI
pip install conda-express
The PyPI package installs the cx release binary built with conda-ship for
your platform.
Upgrading from early releases
Current cx releases bootstrap into ~/.conda/express. Early releases used
~/.cx; upgrading the binary does not migrate that prefix automatically. Keep
~/.cx until you have recreated or archived any environments you still need.
If an old Cargo-installed cx is still on your PATH, remove it because
conda-express no longer publishes new crates.io releases.
See the upgrade guide for commands to export old environments, bootstrap the new prefix, and remove the old directory safely.
Reproducing distribution artifacts
The cx and cxz artifacts published from this repository are built with
conda-ship. This repository keeps the
conda-express distribution defaults and delegates the generic runtime and
builder implementation to conda-ship.
Use this repository's release workflow to reproduce these conda-express artifacts. For custom package sets, binary names, or release channels, use conda-ship directly.
Configuration
The conda-express runtime is defined in pyproject.toml. Pixi solves the
runtime source environment, and conda-ship derives the runtime lock from that
committed lockfile:
[tool.conda-ship]
runtime-name = "cx"
runtime-version = { from = "project-metadata" }
delegate-executable = "conda"
artifact-layout = "online"
source-environment = "runtime"
exclude-packages = ["conda-libmamba-solver"]
condarc-file = "runtime.condarc"
freeze-base = true
docs-url = "https://jezdez.github.io/conda-express/"
install-scheme = "conda-home"
install-name = "express"
CLI reference
cx <conda-args> Bootstrap if needed, then run conda
cx info Show conda and prefix information
cx spawn [ENV] Open a subshell through conda-spawn
cx self <command> Run conda-self commands
CX_PREFIX=DIR cx <conda-args> Use a different managed prefix
CX_BUNDLE=DIR cx <conda-args> Seed automatic bootstrap from a bundle
CX_OFFLINE=1 cx <conda-args> Disable network access during bootstrap
cx --help, cx --version, and every subcommand belong to the installed
conda CLI. The bootstrapper does not reserve its own commands.
Frozen base prefix
The ~/.conda/express prefix is protected with a CEP 22 frozen marker after bootstrap. This prevents accidental modification of the base environment (e.g., conda install numpy into base). Users should create named environments for their work:
cx create -n myenv numpy pandas
cx spawn myenv
Bootstrap also writes constructor-compatible prefix metadata:
conda-meta/history and conda-meta/initial-state.explicit.txt. Conda can
recognize the managed prefix as an environment, and the included conda-self
plugin can use the initial-state snapshot:
cx self reset --snapshot installer-exact
The snapshot belongs to the prefix that was created during its first
bootstrap. Installing a newer cx binary does not replace that snapshot, and
conda self reset does not apply the newer binary's stamped runtime lock.
Building custom binaries
For custom package sets or new distributions, use
conda-ship directly. This repository's build
workflow is release preparation for this repository's cx and cxz
binaries, not a generic downstream builder interface.
Uninstalling
Remove cx with the same method that installed it. For example, use
brew uninstall cx for Homebrew or python -m pip uninstall conda-express
for PyPI. A standalone script installation can be removed by deleting the
installed binary and its PATH entry.
Those operations do not delete ~/.conda/express or its named environments.
Export anything you need before removing that directory manually. Until
conda-self gains a conda-express adapter, there is no cx uninstall command.
How it works
-
Build time: Pixi solves the
runtimesource environment intopixi.lock; the conda-express release workflow asks conda-ship to derive a runtime lock, filter excluded packages, and stamp that lock into the staged binary. -
First run: cx reads the stamped runtime lock, downloads packages from conda-forge, installs them into the prefix, and writes conda-compatible prefix metadata. No repodata fetch or solve needed at runtime.
-
Subsequent runs: cx detects the existing prefix and replaces its own process with the installed
condabinary, passing all arguments through.
Activation model
cx ships with conda-spawn instead of traditional conda activate. There is no need to run conda init or modify shell profiles.
# Optional: expose the managed conda executable directly
export PATH="$HOME/.conda/express/condabin:$PATH"
# Activate an environment (spawns a subshell)
cx spawn myenv
# Deactivate by exiting the subshell
exit
Lockfile format
The stamped runtime lock uses the rattler-lock v6 format (same as pixi.lock). It can be:
- Read by pixi
- Imported by conda-lockfiles
- Checked into version control for reproducibility auditing
License
BSD 3-Clause. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file conda_express-26.5.2.post6-py3-none-win_amd64.whl.
File metadata
- Download URL: conda_express-26.5.2.post6-py3-none-win_amd64.whl
- Upload date:
- Size: 3.8 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e1cbb09e660fc74fa8131c94c872c16d163f3a93ae445ab6e6e3daf8749bc398
|
|
| MD5 |
345bad251925547306a5b34c1d4ad576
|
|
| BLAKE2b-256 |
f3c7aba518409906cf3c2b97e92f808566ac8ca55616ece1b4d6167608669026
|
Provenance
The following attestation bundles were made for conda_express-26.5.2.post6-py3-none-win_amd64.whl:
Publisher:
release.yml on jezdez/conda-express
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
conda_express-26.5.2.post6-py3-none-win_amd64.whl -
Subject digest:
e1cbb09e660fc74fa8131c94c872c16d163f3a93ae445ab6e6e3daf8749bc398 - Sigstore transparency entry: 2213445844
- Sigstore integration time:
-
Permalink:
jezdez/conda-express@37fccc33d801b453ecce2b807b7ead9b49e4e425 -
Branch / Tag:
refs/tags/26.5.2.post6 - Owner: https://github.com/jezdez
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@37fccc33d801b453ecce2b807b7ead9b49e4e425 -
Trigger Event:
push
-
Statement type:
File details
Details for the file conda_express-26.5.2.post6-py3-none-manylinux2014_x86_64.whl.
File metadata
- Download URL: conda_express-26.5.2.post6-py3-none-manylinux2014_x86_64.whl
- Upload date:
- Size: 3.9 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2d58c34c6832afb38024b3c769d0a3fde188ca89ff0254d49d12340fbf37cccd
|
|
| MD5 |
bd1bf0fb2345a611dff06ce1c914ea4c
|
|
| BLAKE2b-256 |
c6f6b4edcbe5716bcd8b3fcb314a2856d348eac9d677d6cc9a9cc0d7ce3364c0
|
Provenance
The following attestation bundles were made for conda_express-26.5.2.post6-py3-none-manylinux2014_x86_64.whl:
Publisher:
release.yml on jezdez/conda-express
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
conda_express-26.5.2.post6-py3-none-manylinux2014_x86_64.whl -
Subject digest:
2d58c34c6832afb38024b3c769d0a3fde188ca89ff0254d49d12340fbf37cccd - Sigstore transparency entry: 2213446562
- Sigstore integration time:
-
Permalink:
jezdez/conda-express@37fccc33d801b453ecce2b807b7ead9b49e4e425 -
Branch / Tag:
refs/tags/26.5.2.post6 - Owner: https://github.com/jezdez
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@37fccc33d801b453ecce2b807b7ead9b49e4e425 -
Trigger Event:
push
-
Statement type:
File details
Details for the file conda_express-26.5.2.post6-py3-none-manylinux2014_aarch64.whl.
File metadata
- Download URL: conda_express-26.5.2.post6-py3-none-manylinux2014_aarch64.whl
- Upload date:
- Size: 3.7 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e96764309778eede5cd03af4eabb2fd78d5064e06a5ae196c9afd9be7d66fb89
|
|
| MD5 |
04bf003102dcd178ce9e10b0d7f5097d
|
|
| BLAKE2b-256 |
cb67a5e5b4e04078f3c404bcac8103079b6fc738ca494db27ca0281d19f51c48
|
Provenance
The following attestation bundles were made for conda_express-26.5.2.post6-py3-none-manylinux2014_aarch64.whl:
Publisher:
release.yml on jezdez/conda-express
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
conda_express-26.5.2.post6-py3-none-manylinux2014_aarch64.whl -
Subject digest:
e96764309778eede5cd03af4eabb2fd78d5064e06a5ae196c9afd9be7d66fb89 - Sigstore transparency entry: 2213447095
- Sigstore integration time:
-
Permalink:
jezdez/conda-express@37fccc33d801b453ecce2b807b7ead9b49e4e425 -
Branch / Tag:
refs/tags/26.5.2.post6 - Owner: https://github.com/jezdez
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@37fccc33d801b453ecce2b807b7ead9b49e4e425 -
Trigger Event:
push
-
Statement type:
File details
Details for the file conda_express-26.5.2.post6-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: conda_express-26.5.2.post6-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 3.4 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7628c07870c1c1a354f2a8de99c8a6e4150e61946787bbfc82a71a2133e486a0
|
|
| MD5 |
119644f2a227e402aa8204cec1cf9d96
|
|
| BLAKE2b-256 |
72d0f90fff98afd60e2f0f338df38f54253e22452ff25879c73cbac5b0c427ae
|
Provenance
The following attestation bundles were made for conda_express-26.5.2.post6-py3-none-macosx_11_0_arm64.whl:
Publisher:
release.yml on jezdez/conda-express
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
conda_express-26.5.2.post6-py3-none-macosx_11_0_arm64.whl -
Subject digest:
7628c07870c1c1a354f2a8de99c8a6e4150e61946787bbfc82a71a2133e486a0 - Sigstore transparency entry: 2213446147
- Sigstore integration time:
-
Permalink:
jezdez/conda-express@37fccc33d801b453ecce2b807b7ead9b49e4e425 -
Branch / Tag:
refs/tags/26.5.2.post6 - Owner: https://github.com/jezdez
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@37fccc33d801b453ecce2b807b7ead9b49e4e425 -
Trigger Event:
push
-
Statement type:
File details
Details for the file conda_express-26.5.2.post6-py3-none-macosx_10_12_x86_64.whl.
File metadata
- Download URL: conda_express-26.5.2.post6-py3-none-macosx_10_12_x86_64.whl
- Upload date:
- Size: 3.6 MB
- Tags: Python 3, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
13a32b2e023cae8552eb709557b15a88a11eb7c4f9bf679a0576f1dfcbcf31c2
|
|
| MD5 |
ae5db17943c331308e9c9064a6e045cf
|
|
| BLAKE2b-256 |
1826b53164636d3653c5bbf7e971e4c4173f492b13d2c8701c99092664fdacdb
|
Provenance
The following attestation bundles were made for conda_express-26.5.2.post6-py3-none-macosx_10_12_x86_64.whl:
Publisher:
release.yml on jezdez/conda-express
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
conda_express-26.5.2.post6-py3-none-macosx_10_12_x86_64.whl -
Subject digest:
13a32b2e023cae8552eb709557b15a88a11eb7c4f9bf679a0576f1dfcbcf31c2 - Sigstore transparency entry: 2213446863
- Sigstore integration time:
-
Permalink:
jezdez/conda-express@37fccc33d801b453ecce2b807b7ead9b49e4e425 -
Branch / Tag:
refs/tags/26.5.2.post6 - Owner: https://github.com/jezdez
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@37fccc33d801b453ecce2b807b7ead9b49e4e425 -
Trigger Event:
push
-
Statement type: