Overview
conda-dist is a command-line tool that converts a Conda environment manifest
into deliverables. It reads a single conda-dist.toml file, resolves the
requested packages, and prepares the build artifacts.
Available output families include:
- Native installers that unpack the environment into a user-specified prefix.
- OCI container images that embed the environment on top of a minimal base.
- Native packages (RPM/DEB) built for Linux targets.
The remaining chapters document the manifest format and describe how each backend consumes it.
Configuration Reference
conda-dist reads a single TOML manifest. Every command consumes the same
configuration, so you describe the environment once and reuse it for installers,
containers, or other outputs. A minimal manifest looks like:
name = "myapp"
version = "1.2.0"
author = "John Doe"
license = "Proprietary"
channels = ["conda-forge"]
platforms = ["linux-64", "osx-arm64"]
[dependencies]
python = "3.11.*"
pandas = "^2.2"
The remaining sections document each supported key, including optional tables for format-specific settings.
Common Settings
These keys apply to every build target and appear at the top level of the manifest.
Required fields
name— ASCII string composed of letters, digits,-,_, or.. Used when naming installers, archives, and tags.version— ASCII string without whitespace. Appended to artifact names and container tags.author— Free-form maintainer identifier bundled into metadata.license— License identifier embedded in native package metadata. Defaults toProprietaryif omitted.channels— Non-empty array of Conda channels evaluated in order of precedence.platforms— Non-empty array of Conda platforms (for examplelinux-64,osx-arm64). Each platform yields a distinct installer executable.
Dependencies
Declare package requirements with a table of Conda match specs:
[dependencies]
python = "3.11.*"
pandas = "^2.2"
Metadata
Populate optional descriptive fields for installers and summary output:
[metadata]
summary = "MyApp command suite"
description = "Command-line utilities for data preparation."
release_notes = "- Initial publication."
featured_packages = ["python", "pandas"]
Virtual packages
conda-dist seeds each platform with sensible defaults for synthetic virtual
packages instead of probing the build host. Override values only when you need
to pin a specific runtime characteristic.
[virtual_packages.default]
linux = "5.15"
libc = { family = "glibc", version = "2.31" }
[virtual_packages.linux-64]
cuda = "12.2"
Use the default table for cross-platform values and add per-platform tables to
override individual targets. Supported keys are linux, osx, win, libc,
and cuda.
Package settings
Configure native RPM/DEB packaging:
[package]
split_deps = false
release = "1"
[package.images.rocky]
type = "rpm"
image = "rockylinux:9"
[package.images.ubuntu]
type = "deb"
image = "ubuntu:24.04"
When enabled, split_deps emits a metapackage plus individual native packages
for each transitive dependency.
The optional release field controls the RPM/DEB release suffix applied to the
base package (defaults to 1).
Each entry under package.images defines a container image keyed by name; the
name is used as the output subdirectory.
Container Settings
[container] configures OCI image output.
[container]
base_image = "gcr.io/distroless/base-debian12"
prefix = "/opt/env"
tag_template = "registry.internal.example.com/analytics/{name}:{version}-py311"
base_image(optional) defaults togcr.io/distroless/base-debian12.prefix(optional) relocates the Conda environment inside the image. Supply an absolute path; the default is/opt/conda.tag_template(optional) renders the final tag. Only{name}and{version}are recognised placeholders. The default template is{name}:{version}.
Container builds emit <name>-container.oci.tar alongside the manifest unless
you override the output location on the command line.
Output Formats
Output formats consume the manifest and emit distributable artifacts. Each one reuses the same dependency resolution step, then applies backend-specific packaging.
- Installers — produce native self-extracting executables per target platform.
- Container images — stage the environment into a minimal base and output an OCI archive.
- Native packages — produce RPM and DEB artifacts for Linux distributions.
Subsequent sections describe the behaviour and outputs of each format.
Installers
conda-dist installer <manifest> produces a native self-extracting installer
for each target platform.
Usage Example
conda-dist installer app.toml
./app-linux-64 /opt/app
/opt/app/bin/python --version
The command caches downloads and writes one native installer executable per
platform (defaulting to <name>-<platform> in the manifest directory). Each
installer unpacks the bundled environment into the installation path you
provide, with no external runtime requirements.
Characteristics
- Output: Native executable archive, one per target platform.
- Installation prefix: User-supplied path, installable anywhere.
- Runtime dependencies: None required on the target host.
- Reproducibility: Bundles the locked package set used at build time.
- Transport: Compressed payload suitable for artifact stores or offline delivery.
Container Images
conda-dist container <manifest> builds an OCI image from the manifest.
Usage Example
conda-dist container app.toml
skopeo copy oci-archive:app-container.oci.tar docker-daemon://app:1.0.0
docker run app:1.0.0 env/bin/python --version
conda-dist container stages the resolved environment on the configured base
image and writes an OCI archive (default <name>-container.oci.tar alongside
the manifest). The example uses skopeo to load the archive into a Docker
daemon; any OCI-aware transport can be substituted.
Characteristics
- Output: OCI archive suitable for use with Docker, Kubernetes, etc.
- Base image: Configurable (defaults to
gcr.io/distroless/base-debian12). - Footprint: Distroless base plus the packaged environment keeps layers minimal.
- Multi-architecture: Multiple platforms yield a single tag backed by per-platform images.
Native Packages
conda-dist package <manifest> builds RPM and DEB archives for Linux targets.
Usage Example
[package.images.rocky]
type = "rpm"
image = "rockylinux:9"
[package.images.ubuntu]
type = "deb"
image = "ubuntu:24.04"
conda-dist package app.toml
Packages are written beneath <output-dir>/<image-name>/, grouped by the image
name from the manifest. The output directory defaults to the manifest directory,
and each image directory contains the generated RPM/DEB artifacts.
Use --image <name> to select a subset of images from the manifest.
Characteristics
- Output: RPM/DEB archives organized per container image.
- Platforms: Supports all Linux targets listed in the manifest.
- Images: Works with docker/podman-compatible distribution images.
- Runtime dependencies: None required on the target host.
CLI Reference
conda-dist
NAME
conda-dist - Build distributable artifacts from Conda environments
SYNOPSIS
conda-dist [–work-dir] [–locked] [–unlock] [–engine] [–engine-flag] [-h|–help] [-V|–version] <subcommands>
DESCRIPTION
Build distributable artifacts from Conda environments
OPTIONS
–work-dir <PATH>
Workspace directory used for cached artifacts (defaults to
<manifest>/.conda-dist)
–locked
Require the existing lockfile and skip solving; fails if the lockfile is
stale or missing
–unlock
Regenerate the lockfile even if one already exists
–engine <PATH>
Path to the container engine binary (defaults to docker, then podman)
–engine-flag <FLAG>
Extra flags passed directly to the container engine (repeatable)
-h, –help
Print help
-V, –version
Print version
SUBCOMMANDS
conda-dist-lock(1)
Update or validate the lockfile without producing artifacts
conda-dist-installer(1)
Build self-extracting installers
conda-dist-container(1)
Build container images embedding the environment
conda-dist-package(1)
Build native system packages (rpm/deb) using containerized installers
conda-dist-help(1)
Print this message or the help of the given subcommand(s)
VERSION
v0.3.0
conda-dist container
NAME
container - Build container images embedding the environment
SYNOPSIS
conda-dist container [–platform] [–oci-output] [-h|–help] [MANIFEST]
DESCRIPTION
Build container images embedding the environment
OPTIONS
–platform <PLATFORM>
Restrict the build to a single target platform
–oci-output <PATH>
Path to write the resulting OCI archive (defaults to
<manifest-dir>/<name>-container.oci.tar)
-h, –help
Print help
[MANIFEST] [default: conda-dist.toml]
Path to the conda-dist manifest (conda-dist.toml)
conda-dist installer
NAME
installer - Build self-extracting installers
SYNOPSIS
conda-dist installer [–output-dir] [–installer-platform] [-h|–help] [MANIFEST]
DESCRIPTION
Build self-extracting installers
OPTIONS
–output-dir <PATH>
Optional directory to write the installer binary
–installer-platform <PLATFORM> [default: all]
Select which installer platform(s) to build
-h, –help
Print help
[MANIFEST] [default: conda-dist.toml]
Path to the conda-dist manifest (conda-dist.toml)
conda-dist lock
NAME
lock - Update or validate the lockfile without producing artifacts
SYNOPSIS
conda-dist lock [-h|–help] [MANIFEST]
DESCRIPTION
Update or validate the lockfile without producing artifacts
OPTIONS
-h, –help
Print help
[MANIFEST] [default: conda-dist.toml]
Path to the conda-dist manifest (conda-dist.toml)
conda-dist package
NAME
package - Build native system packages (rpm/deb) using containerized installers
SYNOPSIS
conda-dist package [–image] [–platform] [–output-dir] [-h|–help] [MANIFEST]
DESCRIPTION
Build native system packages (rpm/deb) using containerized installers
OPTIONS
–image <NAME>
Restrict native packaging to specific image name(s) from the manifest
–platform <PLATFORM>
Restrict native packaging to specific target platform(s) (defaults to
host platform)
–output-dir <PATH>
Output directory for generated packages (defaults to <manifest-dir>)
-h, –help
Print help
[MANIFEST] [default: conda-dist.toml]
Path to the conda-dist manifest (conda-dist.toml)
Developer Notes
This section covers conda-dist internals and development notes.
Packaging Implementation
This section documents how conda-dist produces the three output types:
Self-Extracting Installer
Inputs
The installer output combines two inputs:
- A platform-specific installer binary embedded in the
conda-distbuild (conda-dist/installers/*compiled into the binary viabuild.rs). - A tar.gz payload containing the staged channel.
Payload Layout
The payload is a gzipped tar archive with a single root directory named after the environment. The archive includes:
conda-lock.yml(the lockfile copied into the channel directory).- The channel subdirectories:
noarch/and the target platform subdir (for examplelinux-64/). repodata.jsonand any other channel index artifacts in the root of each subdir.
Self-Extracting Binary Layout
The final installer file is created by appending metadata and payload data to the installer stub. The layout is:
[installer bytes]
[bundle metadata JSON]
[u64 metadata length, little-endian]
[tar.gz payload bytes]
[u64 payload length, little-endian]
"CONDADIST!"
The embedded metadata JSON matches the bundle metadata from the manifest. The trailing length fields and magic marker allow the installer to find the payload and metadata by reading backward from the end of the executable.
Runtime Behavior
At install time the installer:
- Reads the embedded metadata and payload length footer from its own executable.
- Extracts the tar.gz payload to a temporary directory.
- Loads the lockfile from the extracted channel directory.
- Uses the extracted channel (a file:// URL) to install the locked environment into the requested prefix.
OCI/Docker Images
Container images are built by running the self-extracting installer during the image build.
Build Behavior
- Installers are prepared for the requested Linux platforms and staged in the build context.
- A multi-stage Dockerfile is generated. The first stage holds the installers; the final stage runs the matching installer to materialize the environment at the configured prefix.
- The image build is multi-platform; each platform run uses its corresponding installer.
- The resulting image sets
CONDA_PREFIXandPATHto the configured prefix. - The build output is exported as a multi-architecture OCI archive.
Native Packages (RPM/DEB)
Native packages are built in containers. The build uses a self-extracting installer to materialize the environment inside the container before packaging it.
Build Behavior
- Installers are prepared for the requested platforms.
- A per-platform
package_plan.tsvdescribes which native packages to build and where their payloads and metadata live in the packaging workspace. - The packaging container receives the installer, the package plan, and an output directory via bind mounts.
- Inside the container, the packaging script installs the environment via the installer.
- Inside the container, the script runs
rpmbuildordpkg-deband writes artifacts to the output directory.
split_deps = false (Single Package)
When split_deps is disabled:
- The base package contains the full environment payload.
- No per-dependency subpackages are generated.
- The resulting RPM/DEB is self-contained.
split_deps = true (One Package per Conda Package)
When split_deps is enabled:
- The base package is a metapackage with no payload.
- One dependency package is created per conda package, containing only that package’s files.
- For Python noarch packages, the native package release is suffixed with the Python major/minor version (for example
py311) so builds against different interpreters remain distinct.
To ensure dependency packages are only installed alongside the base metapackage, conda-dist encodes a dependency cycle:
- The base package depends on each dependency package with exact version+build pins and provides
lock-<package>for each dependency. - Each dependency package depends on its corresponding
lock-<package>virtual provide.
This makes the base package act as the lockfile while still allowing the environment to be split into native packages.
Example dependency cycle (environment name: my-app):
my-app (metapackage)
Depends: my-app-numpy (= 1.26.4-0), my-app-python (= 3.12.1-0), ...
Provides: lock-my-app-numpy, lock-my-app-python, ...
my-app-numpy
Depends: lock-my-app-numpy
my-app-python
Depends: lock-my-app-python