conda-express (cx)
A lightweight, single-binary bootstrapper for conda, powered by rattler. The cx binary is short for conda express.
cx replaces the miniconda/constructor installation pattern with a ~17 MB static binary that bootstraps a fully functional conda environment in seconds.
Quick start
# Bootstrap a conda installation (first run only, ~3–5 s)
# Use conda normally — cx delegates transparently
# Activate environments using conda-spawn (no shell init needed)
On first use, cx automatically installs conda and its plugins into ~/.cx from an embedded lockfile. Subsequent invocations hand off directly to the installed conda binary with no overhead.
What gets installed
cx installs a minimal conda stack from conda-forge:
| Package | Role |
|---|---|
| python >= 3.12 | Runtime |
| conda >= 25.1 | Package manager |
| conda-rattler-solver | Rust-based solver (replaces libmamba) |
| conda-spawn | Subprocess-based environment activation |
| conda-pypi | PyPI interoperability |
| conda-self | Base environment self-management |
The conda-libmamba-solver and its 27 exclusive native dependencies (libsolv, libarchive, libcurl, spdlog, etc.) are excluded by default, reducing the install from 113 to 86 packages.
Installation
Installer script (recommended)
macOS / Linux:
|
Windows (PowerShell):
powershell -ExecutionPolicy ByPass -c "irm https://jezdez.github.io/conda-express/get-cx.ps1 | iex"
The installer detects your platform, downloads the right binary, verifies the checksum, updates your shell profile / PATH, and runs cx bootstrap. Customize with environment variables:
CX_INSTALL_DIR— where to place the binary (default:~/.local/binor%USERPROFILE%\.local\bin)CX_VERSION— specific version to install (default:latest)CX_NO_PATH_UPDATE— set to skip shell profile / PATH modificationCX_NO_BOOTSTRAP— set to skip runningcx bootstrap
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 |
Each file has a matching .sha256 checksum.
From PyPI
From crates.io
The package is published as conda-express on PyPI and crates.io.
Building from source
Requires pixi (recommended) or Rust (edition 2024).
With pixi (recommended)
pixi manages the Rust toolchain from conda-forge for reproducible builds:
With system Rust
# Build (first build solves packages at compile time — needs network)
# Binary is at target/release/cx
The first build runs a compile-time solve via build.rs, generating a rattler-lock v6 lockfile that gets embedded into the binary. Subsequent builds reuse the cached lockfile unless pixi.toml changes.
Configuration
Package specs, channels, and exclusions live in the [tool.cx] section of pixi.toml:
[]
= ["conda-forge"]
= [
"python >=3.12",
"conda >=25.1",
"conda-rattler-solver",
"conda-spawn",
"conda-pypi",
"conda-self",
]
= ["conda-libmamba-solver"]
Edit this section to customize what cx installs, then rebuild.
CLI reference
cx bootstrap [OPTIONS] Bootstrap a fresh conda installation
--force Re-bootstrap even if prefix exists
--prefix DIR Target directory (default: ~/.cx)
--channel CH Channels (default: conda-forge)
--package PKG Additional packages to install
--exclude PKG Packages to exclude (default: conda-libmamba-solver)
--no-exclude Disable default exclusions
--no-lock Ignore embedded lockfile, do a live solve
--lockfile PATH Use an external lockfile instead
cx status [--prefix DIR] Show cx installation status
cx shell [ENV] Alias for conda spawn (activate via subshell)
cx help Getting-started guide
cx <conda-args> Passed through to conda
Disabled commands
cx uses conda-spawn instead of traditional shell-based activation. The following commands are intentionally disabled:
| Command | Instead |
|---|---|
conda activate / deactivate |
cx shell myenv |
conda init |
Add condabin to your PATH (see below) |
Frozen base prefix
The ~/.cx 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:
Updating the base installation is handled by conda self update (via conda-self).
How it works
-
Compile time:
build.rsreads[tool.cx]frompixi.toml, solves dependencies using rattler, filters excluded packages, and writes a rattler-lock v6 lockfile embedded into the binary. -
First run: cx parses the embedded lockfile, downloads packages from conda-forge, and installs them into the prefix. 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.
# Add cx to PATH (one-time setup)
# Activate an environment (spawns a subshell)
# Deactivate by exiting the subshell
Lockfile format
The embedded lockfile 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.