Features#

Single-binary bootstrapper#

Bootstrap conda, create an environment, and activate it

cx is a single static binary (7-11 MB depending on platform) written in Rust. It requires no Python, no installer framework, and no shell modifications. Download it, run it, and you have a working conda installation.

Compile-time lockfile#

build.rs performs a full dependency solve at cargo build time using rattler crates, producing a rattler-lock v6 lockfile that is embedded into the binary. At runtime, bootstrap skips repodata fetching and solving entirely — it downloads and installs packages directly from the locked URLs.

This gives cx deterministic, reproducible bootstraps with ~3–5 second install times.

Package exclusion#

conda on conda-forge hard-depends on conda-libmamba-solver, which pulls in 27 native dependencies (libsolv, libarchive, libcurl, spdlog, etc.). Since cx uses conda-rattler-solver instead, these are unnecessary.

cx removes them via a post-solve transitive dependency pruning algorithm: after the solver produces a complete solution, cx identifies packages that are exclusively required by the excluded packages and removes them. This reduces the install from 113 to 86 packages.

conda-rattler-solver#

cx configures conda-rattler-solver as the default solver via .condarc. This solver is based on resolvo, the fastest SAT solver in the conda ecosystem, and ships as a pure Python package with py-rattler wheels.

conda-spawn activation#

cx delegates conda commands transparently

cx ships with conda-spawn and disables traditional conda activate/deactivate/init. Instead:

cx shell myenv          # spawns a subshell with myenv activated
exit                    # leaves the environment

No .bashrc/.zshrc modifications required. Just add ~/.cx/condabin to your PATH.

cx shell alias#

cx shell is a convenience alias for conda spawn. It works identically:

cx shell myenv          # same as: conda spawn myenv

conda-workspaces#

Workspaces and tasks with cx

cx includes conda-workspaces, which adds project-scoped multi-environment workspace management and a built-in task runner to conda. After bootstrap, two new subcommands are available:

# Initialize a workspace and install environments
cx workspace init --name my-project
cx workspace add python numpy
cx workspace install

# Define and run tasks
cx task run test
cx task list

conda-workspaces reads workspace manifests from conda.toml, pixi.toml, or pyproject.toml — making it compatible with existing pixi projects. See the conda-workspaces documentation for the full feature set.

Frozen base prefix (CEP 22)#

cx status, cx info, and cx env list

After bootstrap, cx writes a conda-meta/frozen marker file per CEP 22. This protects the base prefix from accidental modification. Users should create named environments for their work:

cx create -n myenv numpy pandas
cx shell myenv

Auto-bootstrap#

If the prefix doesn’t exist when you run a conda command, cx automatically bootstraps before executing:

# First time: bootstraps ~/.cx, then creates the environment
cx create -n myenv python=3.12

External lockfile support#

For custom deployments, you can override the embedded lockfile:

cx bootstrap --lockfile /path/to/custom.lock

Or skip the lockfile entirely for a live solve:

cx bootstrap --no-lock

Offline bootstrap#

cx supports fully offline, air-gapped bootstrap from a local directory of package archives or from a previously populated package cache. This enables deployment in restricted-network environments and native installers (macOS PKG, Windows MSI) that bundle cx alongside a package payload.

Two flags control this behavior:

  • --payload DIR points to a directory of .conda / .tar.bz2 archives. cx pre-populates the rattler package cache from this directory, then installs from cache. Without --offline, missing packages fall back to network download.

  • --offline disables all network access. All packages must be available locally (in the cache or payload). Incompatible with --no-lock.

# Re-use packages from a previous bootstrap (no network)
cx bootstrap --prefix /opt/conda --offline

# Install from a bundled payload directory (fully air-gapped)
cx bootstrap --payload ./packages/ --offline

Both flags can also be set via the CX_PAYLOAD and CX_OFFLINE environment variables, making them easy to use from native installer post-install scripts.

Self-contained binary (cxz)#

cxz takes offline bootstrap one step further: it embeds the package archives themselves into the binary. One 50-95 MB file (varies by platform), zero network access, drop it anywhere.

cx (7-11 MB)              cxz (50-95 MB)
┌──────────────┐          ┌──────────────────┐
│  cx binary   │          │  cx binary       │
│  (7-11 MB)   │          │  (7-11 MB)       │
├──────────────┤          ├──────────────────┤
│  lockfile    │          │  lockfile        │
│  (39 KB)     │          │  (39 KB)         │
│              │          ├──────────────────┤
│              │          │  payload.tar.zst │
│              │          │  (40-85 MB)      │
└──────────────┘          └──────────────────┘

cxz is the same codebase as cx, built with CX_EMBED_PAYLOAD=1. It detects its embedded payload automatically and behaves as if --payload --offline were passed. All other flags and subcommands work identically.

It is distributed via GitHub Releases (alongside cx) and as a pre-bootstrapped Docker image. See the custom builds guide for build instructions.

Uninstall (cx uninstall)#

cx provides a clean uninstall command that reverses the bootstrap:

cx uninstall

This will:

  1. List what will be removed (prefix, named environments, cx binary)

  2. Ask for confirmation (--yes to skip)

  3. Remove the conda prefix and all environments

  4. Remove the cx binary

  5. Clean up PATH entries from shell profiles

GitHub Action for custom builds#

cx ships a composite GitHub Action and a reusable workflow that let you build custom cx binaries with your own package set baked in. The build performs a full compile-time dependency solve, producing a self-contained binary with an embedded lockfile — just like the official cx releases.

This is powered by the same environment variable overrides that work locally, but wrapped in a ready-to-use Action.

See the GitHub Action reference for inputs, outputs, and behavior. For a step-by-step walkthrough, see the custom builds guide.

conda in the browser (cx-wasm)#

cx-wasm compiles the same rattler-based solver and package extractor to WebAssembly, enabling conda install to run entirely client-side in a JupyterLite notebook.

%load_ext conda_emscripten
%conda install lz4
import lz4

This runs real conda — the actual Python package manager, not a reimplementation — with cx-wasm replacing the native-code bottlenecks via conda’s plugin API. Packages with C extensions (like lz4) work after installation thanks to automatic shared library loading.

A shard prefetch runs at kernel startup, fetching all repodata shards in parallel via async JavaScript fetch(). This means the solve phase makes zero network requests — a typical %conda install lz4 completes in ~3.5 seconds.

See the browser guide for details, or try the live demo.

Multi-platform support#

cx builds and tests on 5 platforms via GitHub Actions:

Platform

Runner

linux-x64

ubuntu-latest

linux-aarch64

ubuntu-24.04-arm

macos-x64

macos-15-large

macos-arm64

macos-latest

windows-x64

windows-latest

PyPI and crates.io distribution#

cx is published as conda-express on both PyPI and crates.io:

pip install conda-express       # from PyPI
cargo install conda-express     # from crates.io

Both use trusted publishing (OIDC) for secure, tokenless releases.