A lightweight, single-binary conda bootstrapper — powered by rattler
Project description
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)
cx bootstrap
# Use conda normally — cx delegates transparently
cx install -n myenv numpy pandas
cx create -n science python=3.12 scipy
# Activate environments using conda-spawn (no shell init needed)
cx shell myenv
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
Homebrew (recommended)
The easiest way to install 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 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.
Docker
A minimal, hardened multi-arch image (~37 MB) is published to GHCR on every release:
docker run --rm -v cx-data:/home/nonroot/.cx ghcr.io/jezdez/conda-express bootstrap
The image runs as non-root (uid 65532), works with --read-only, and includes provenance attestations and SBOMs. Docker Desktop on macOS and Windows automatically selects the right architecture (linux/amd64 or linux/arm64).
# Run conda commands through cx
docker run --rm -v cx-data:/home/nonroot/.cx 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 bootstrap && 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 bootstrap && cx create -n app python numpy pandas
FROM gcr.io/distroless/cc-debian12:nonroot
COPY --from=conda-builder /home/nonroot/.cx/envs/app /opt/conda
From PyPI
pip install conda-express
From crates.io
cargo install conda-express
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:
git clone https://github.com/jezdez/conda-express.git
cd conda-express
pixi run build # cargo build --release
pixi run test # cargo test
pixi run lint # fmt-check + clippy
With system Rust
git clone https://github.com/jezdez/conda-express.git
cd conda-express
# Build (first build solves packages at compile time — needs network)
cargo build --release
# Binary is at target/release/cx
./target/release/cx --help
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:
[tool.cx]
channels = ["conda-forge"]
packages = [
"python >=3.12",
"conda >=25.1",
"conda-rattler-solver",
"conda-spawn",
"conda-pypi",
"conda-self",
]
exclude = ["conda-libmamba-solver"]
Edit this section to customize what cx installs, then rebuild. You can also override these values at build time using environment variables — see Building custom cx binaries below.
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 uninstall [OPTIONS] Remove cx, conda prefix, and all environments
--prefix DIR Target directory (default: ~/.cx)
-y, --yes Skip confirmation prompt
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:
cx create -n myenv numpy pandas
cx shell myenv
Updating the base installation is handled by conda self update (via conda-self).
Building custom cx binaries
You can build a cx binary with your own set of packages using the composite GitHub Action or the reusable workflow.
Composite action (uses: jezdez/conda-express@main)
Use in a step within your own workflow. You control the platform matrix:
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: jezdez/conda-express@main
id: cx
with:
packages: "python >=3.12, conda >=25.1, conda-rattler-solver, conda-spawn, numpy, pandas"
- uses: actions/upload-artifact@v4
with:
name: ${{ steps.cx.outputs.asset-name }}
path: ${{ steps.cx.outputs.binary-path }}
Reusable workflow
Builds all 5 platforms in one call:
jobs:
build-cx:
uses: jezdez/conda-express/.github/workflows/build.yml@main
with:
packages: "python >=3.12, conda >=25.1, conda-rattler-solver, conda-spawn, numpy, pandas"
Build-time environment variables
When building from source, you can override the package configuration without editing pixi.toml:
| Variable | Overrides | Format |
|---|---|---|
CX_PACKAGES |
[tool.cx].packages |
Comma-separated match specs |
CX_CHANNELS |
[tool.cx].channels |
Comma-separated channel names |
CX_EXCLUDE |
[tool.cx].exclude |
Comma-separated package names |
CX_PACKAGES="python >=3.12, conda >=25.1, numpy" pixi run build
Uninstalling
To completely remove cx, the conda prefix, all environments, and the cx binary:
cx uninstall
This will show what will be removed and ask for confirmation. Use --yes to skip the prompt. The command also cleans up PATH entries from shell profiles that were added by the installer.
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)
export PATH="$HOME/.cx/condabin:$PATH"
# Activate an environment (spawns a subshell)
cx shell myenv
# Deactivate by exiting the subshell
exit
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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
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-0.5.3.tar.gz.
File metadata
- Download URL: conda_express-0.5.3.tar.gz
- Upload date:
- Size: 276.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
69cd68452a6035e0edd6e75442ad3b48926afbcb0b86c5f376f775f3fe22d4b8
|
|
| MD5 |
3ccc6e33d01470c1fbfea0d51eb3e24f
|
|
| BLAKE2b-256 |
a99f17f0299f8e0a6dd1c353ff9205fe5500a893f70c4f6275711e60a4ad232d
|
Provenance
The following attestation bundles were made for conda_express-0.5.3.tar.gz:
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-0.5.3.tar.gz -
Subject digest:
69cd68452a6035e0edd6e75442ad3b48926afbcb0b86c5f376f775f3fe22d4b8 - Sigstore transparency entry: 1201756263
- Sigstore integration time:
-
Permalink:
jezdez/conda-express@cecf17c18b4e6d3bc901e209af463bfc863fe55c -
Branch / Tag:
refs/tags/0.5.3 - Owner: https://github.com/jezdez
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@cecf17c18b4e6d3bc901e209af463bfc863fe55c -
Trigger Event:
release
-
Statement type:
File details
Details for the file conda_express-0.5.3-py3-none-win_amd64.whl.
File metadata
- Download URL: conda_express-0.5.3-py3-none-win_amd64.whl
- Upload date:
- Size: 4.8 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
25404b04832b390a5e64ea044df6c0ecad479ba6600969c03962e3267e3bd090
|
|
| MD5 |
f0552647af819ad68577c0165c982f77
|
|
| BLAKE2b-256 |
d501fe62b926912e49771f632b97f89c9ec88fd694bb827e4fd9426cd2dd6f68
|
Provenance
The following attestation bundles were made for conda_express-0.5.3-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-0.5.3-py3-none-win_amd64.whl -
Subject digest:
25404b04832b390a5e64ea044df6c0ecad479ba6600969c03962e3267e3bd090 - Sigstore transparency entry: 1201756371
- Sigstore integration time:
-
Permalink:
jezdez/conda-express@cecf17c18b4e6d3bc901e209af463bfc863fe55c -
Branch / Tag:
refs/tags/0.5.3 - Owner: https://github.com/jezdez
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@cecf17c18b4e6d3bc901e209af463bfc863fe55c -
Trigger Event:
release
-
Statement type:
File details
Details for the file conda_express-0.5.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: conda_express-0.5.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 4.8 MB
- Tags: Python 3, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8d3f67114bb3eaa55a4ad3a62f9dbb69ce6bb3ad74b47dd78caf972604099820
|
|
| MD5 |
2b7739ba31ca0718639c2e77b6e3662f
|
|
| BLAKE2b-256 |
cd1e074d54bc48d228381eba92214a6a613a3184d6271315d91b6fbdb0a1a9a0
|
Provenance
The following attestation bundles were made for conda_express-0.5.3-py3-none-manylinux_2_17_x86_64.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-0.5.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
8d3f67114bb3eaa55a4ad3a62f9dbb69ce6bb3ad74b47dd78caf972604099820 - Sigstore transparency entry: 1201756308
- Sigstore integration time:
-
Permalink:
jezdez/conda-express@cecf17c18b4e6d3bc901e209af463bfc863fe55c -
Branch / Tag:
refs/tags/0.5.3 - Owner: https://github.com/jezdez
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@cecf17c18b4e6d3bc901e209af463bfc863fe55c -
Trigger Event:
release
-
Statement type:
File details
Details for the file conda_express-0.5.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: conda_express-0.5.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 4.7 MB
- Tags: Python 3, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a76da868366a7948258b5b18a49b777996cda64de87b15127d77e7ef3a80f136
|
|
| MD5 |
e25e109e168819bbc7a018bb39cf78a1
|
|
| BLAKE2b-256 |
894bdfefcde41601dc8b2f2a9f8745c3b9491cb4e5d4f0b96b261d7995045ff4
|
Provenance
The following attestation bundles were made for conda_express-0.5.3-py3-none-manylinux_2_17_aarch64.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-0.5.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
a76da868366a7948258b5b18a49b777996cda64de87b15127d77e7ef3a80f136 - Sigstore transparency entry: 1201756518
- Sigstore integration time:
-
Permalink:
jezdez/conda-express@cecf17c18b4e6d3bc901e209af463bfc863fe55c -
Branch / Tag:
refs/tags/0.5.3 - Owner: https://github.com/jezdez
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@cecf17c18b4e6d3bc901e209af463bfc863fe55c -
Trigger Event:
release
-
Statement type:
File details
Details for the file conda_express-0.5.3-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: conda_express-0.5.3-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 4.3 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
930105331cdc50eace2de5dbfc1920bc626d0bd930a637bd050e67353e42c6c3
|
|
| MD5 |
f7f0be49a671f2ed849913d3abb48300
|
|
| BLAKE2b-256 |
b3e76edc90446940aaeff18e2deeac41793e39dbb7dc802b32c8b1902e216e3b
|
Provenance
The following attestation bundles were made for conda_express-0.5.3-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-0.5.3-py3-none-macosx_11_0_arm64.whl -
Subject digest:
930105331cdc50eace2de5dbfc1920bc626d0bd930a637bd050e67353e42c6c3 - Sigstore transparency entry: 1201756411
- Sigstore integration time:
-
Permalink:
jezdez/conda-express@cecf17c18b4e6d3bc901e209af463bfc863fe55c -
Branch / Tag:
refs/tags/0.5.3 - Owner: https://github.com/jezdez
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@cecf17c18b4e6d3bc901e209af463bfc863fe55c -
Trigger Event:
release
-
Statement type:
File details
Details for the file conda_express-0.5.3-py3-none-macosx_10_12_x86_64.whl.
File metadata
- Download URL: conda_express-0.5.3-py3-none-macosx_10_12_x86_64.whl
- Upload date:
- Size: 4.5 MB
- Tags: Python 3, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
82df3b7cdf7ece521fc4903049ef9017349ee50fa1d37b1b6449690665c8954e
|
|
| MD5 |
7fd886267bf329e4fc86c535c0de8660
|
|
| BLAKE2b-256 |
fef99e98f3f4cfd4917bec3312fd15d60049039b9e0f4633141f649ec5ab73dd
|
Provenance
The following attestation bundles were made for conda_express-0.5.3-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-0.5.3-py3-none-macosx_10_12_x86_64.whl -
Subject digest:
82df3b7cdf7ece521fc4903049ef9017349ee50fa1d37b1b6449690665c8954e - Sigstore transparency entry: 1201756465
- Sigstore integration time:
-
Permalink:
jezdez/conda-express@cecf17c18b4e6d3bc901e209af463bfc863fe55c -
Branch / Tag:
refs/tags/0.5.3 - Owner: https://github.com/jezdez
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@cecf17c18b4e6d3bc901e209af463bfc863fe55c -
Trigger Event:
release
-
Statement type: