Build Your First Runtime#

This tutorial builds a local conda runtime named demo from either a conda-workspaces project or a Pixi project.

You will create a small project, lock it, build a runtime binary, bootstrap that runtime into a temporary install path, and then remove it again.

Before You Start#

You need:

Install the tools in an environment where you want to run the builder:

conda create -n cs-demo -c conda-forge python pip conda-workspaces
conda activate cs-demo
python -m pip install conda-ship

Check that both commands are available:

conda ship --help
conda workspace --help
conda create -n cs-demo -c conda-forge python pip pixi
conda activate cs-demo
python -m pip install conda-ship

Check that both commands are available:

cs --version
pixi --version

Create A Project#

Create an empty project directory:

mkdir demo-runtime
cd demo-runtime

Then choose the manifest tool you want to use. The two paths produce the same runtime intent: a ship environment containing conda itself, the rattler solver plugin, and conda-spawn for demo shell.

Create a conda.toml:

conda workspace init --format conda --name demo-runtime

Add the runtime packages to a ship feature. conda workspace add creates the matching ship environment in the manifest:

conda workspace add --feature ship --no-lockfile-update \
  "python>=3.12" \
  "conda>=25.1" \
  conda-rattler-solver \
  "conda-spawn>=0.1.0"

Add conda-ship’s build policy:

cat >> conda.toml <<'TOML'

[tool.conda-ship]
runtime = "demo"
runtime-version = "0.1.0"
delegate = "conda"
layout = "online"
source-environment = "ship"
exclude = ["conda-libmamba-solver"]
TOML

Create a pixi.toml:

pixi init --channel conda-forge

Add the ship feature, ship environment, and conda-ship build policy:

cat >> pixi.toml <<'TOML'

[feature.ship.dependencies]

[environments]
ship = { features = ["ship"], no-default-feature = true }

[tool.conda-ship]
runtime = "demo"
runtime-version = "0.1.0"
delegate = "conda"
layout = "online"
source-environment = "ship"
exclude = ["conda-libmamba-solver"]
TOML

Use Pixi’s native add command to put packages in the ship feature:

pixi add --feature ship --no-install \
  "python>=3.12" \
  "conda>=25.1" \
  conda-rattler-solver \
  "conda-spawn>=0.1.0"

Lock The Project#

Solve the source lockfile with the tool that owns the manifest:

conda workspace lock

This writes conda.lock.

pixi lock

This writes pixi.lock. The earlier pixi add --no-install command may have already refreshed it; running pixi lock here makes the tutorial state explicit.

conda-ship consumes the matching lockfile; it does not solve directly from loose package names during normal builds. The builder will derive its own runtime lock from this source lockfile.

Inspect The Package Set#

Run a preflight check before building. This derives the runtime package set, applies exclusions, and prints the selected packages without writing files:

conda ship inspect
cs inspect

The output lists the manifest and lockfile conda-ship selected, each locked platform, and the package set for your current platform.

Build The Runtime#

Build an online runtime named demo:

conda ship build
cs build

The generated runtime is written to dist/demo on Unix and dist/demo.exe on Windows.

An online runtime contains the lockfile and runtime metadata. It downloads conda package archives when it bootstraps.

Smoke-Test The Runtime#

For this tutorial, bootstrap the generated runtime into a temporary local path to prove that the artifact works:

mkdir -p .tmp
./dist/demo --path "$PWD/.tmp/demo" bootstrap

This creates a conda installation managed by the demo runtime. This local bootstrap is only a smoke test; a real downstream distribution should document how its users install and update the runtime it publishes.

Note

The explicit --path keeps this tutorial install inside the project directory. Published runtimes should document their normal install location and reserve --path for local testing or advanced overrides.

Check it:

./dist/demo --path "$PWD/.tmp/demo" status

The status output shows the install path, configured channels, package metadata, installed package count, and delegate executable path.

Clean up the temporary install:

./dist/demo --path "$PWD/.tmp/demo" uninstall --yes

Optional: Build An Embedded Runtime#

The embedded layout puts compressed package archives inside the generated binary. This makes the build slower and the binary larger, but bootstrap no longer needs to download package archives.

conda ship build --layout embedded
cs build --layout embedded

Embedded runtimes use the z suffix, so this stages dist/demoz on Unix and dist/demoz.exe on Windows.

Smoke-test it:

./dist/demoz --path "$PWD/.tmp/demoz" bootstrap
./dist/demoz --path "$PWD/.tmp/demoz" status
./dist/demoz --path "$PWD/.tmp/demoz" uninstall --yes

What You Learned#

You created a small workspace project, solved it, built an online runtime, and used that binary to install and manage its own conda prefix in a temporary smoke test.

For a real downstream distribution, choose a runtime name owned by that distribution, keep its package choices in the source manifest, and publish the staged files from dist/.