Locking and reproducible installs#

conda-workspaces generates a conda.lock file in YAML format using a rattler-lock-derived schema with a conda-workspaces-owned version byte. The lockfile records the resolved package inventory for every environment and platform that the workspace declares.

Changed in version 0.4.0: conda workspace lock now writes a single conda.lock that covers every platform declared by each environment, not just the host platform. Target-platform solves run with context._subdir overridden so conda’s virtual package plugins (__linux, __osx, __win) match the target platform.

Added in version 0.4.0: --platform <subdir> (repeatable) restricts the lock run to a subset of declared platforms. Unknown platforms raise PlatformError before any solve runs. --skip-unsolvable keeps locking the remaining (environment, platform) pairs when an individual solve fails, aggregating the failures into AllTargetsUnsolvableError only if every pair fails. SolveError now names the target platform for easier CI triage.

The conda workspace lock command runs the solver and records the solution. It does not require environments to be installed first.

# Generate or update the lockfile for every platform declared in the manifest
conda workspace lock

# Lock only a subset of platforms into an explicit fragment
conda workspace lock --platform linux-64 --platform osx-arm64 \
  --output conda.lock.selected-platforms

# Keep solvable pairs in an explicit fragment
conda workspace lock --skip-unsolvable --output conda.lock.solvable

# Install from lockfile, validating freshness against the manifest
conda workspace install --locked

# Install from lockfile as-is without checking freshness
conda workspace install --frozen

conda workspace lock solves every environment for every platform it declares in the manifest. Each solve runs with conda’s context._subdir pointed at the target platform so virtual packages (__linux, __osx, __win) match the target, not the host. Pin tighter constraints with CONDA_OVERRIDE_* or the [system-requirements] table when cross-compiling, for example to fix a minimum __glibc version when solving linux-64 from macOS.

--environment, --platform, and --skip-unsolvable can produce an incomplete result, so they require --output. An unfiltered lock is the only workspace lock form that implicitly replaces the canonical conda.lock. Pass --output conda.lock when replacement with a filtered result is intentional.

Solves are fail-fast by default. The first platform that cannot be resolved raises an error that names the environment and the platform, and no lockfile is written. Pass --skip-unsolvable to keep locking the remaining pairs into an explicit --output path, emitting a yellow Skipping ... line for each one that failed. If every pair fails, the command still raises with an aggregated summary rather than writing an empty lockfile. Non-solver errors such as a missing channel or invalid manifest always abort regardless of the flag.

The canonical lockfile contains all environments and their resolved packages:

version: 1
environments:
  default:
    channels:
      - url: https://conda.anaconda.org/conda-forge/
    packages:
      linux-64:
        - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.0-...
  test:
    channels:
      - url: https://conda.anaconda.org/conda-forge/
    packages:
      linux-64:
        - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.0-...
        - conda: https://conda.anaconda.org/conda-forge/linux-64/pytest-8.0.0-...
packages:
  - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.0-...
    sha256: abc123...
    depends:
      - libffi >=3.4
    # ...

Automatic lockfile management#

conda workspace install checks whether the lockfile satisfies the manifest before deciding how to install. When the lockfile covers all declared environments, channels, platforms, and dependency specs, it installs directly from the lockfile with no solver needed. When the lockfile is missing or out of date, it falls back to a full solve and regenerates conda.lock.

This means day-to-day installs are fast while the lockfile stays current when the manifest changes. The check compares the manifest’s dependency specs against locked package versions, so whitespace or comment changes do not trigger a re-solve.

With -e / --environment, only the selected prefix is installed or updated. The solve path covers every declared environment and platform when producing or previewing the canonical conda.lock. Use conda workspace lock -e <environment> --output <fragment> when a partial lock artifact is intentional.

Lockfile state

Default behavior

--locked

--frozen

--no-lock

Satisfiable

Install from lockfile

Install from lockfile

Install from lockfile

Full solve

Not satisfiable

Full solve + update lockfile

Error

Install from lockfile

Full solve

Missing

Full solve + create lockfile

Error

Error

Full solve

Use --no-lock to force a full solve even when the lockfile is satisfiable, for example to pick up channel updates without editing the manifest.

--force-reinstall controls prefix replacement independently of lockfile selection. It recreates prefixes when using a satisfiable lockfile, --locked, --frozen, or CI strict mode. Combine it with --no-lock when both a fresh solve and prefix recreation are required.

Lock freshness indicator#

conda workspace info shows the lockfile status:

conda workspace info

The Lockfile row shows up-to-date (green), out-of-date (yellow), or missing (red). The JSON output includes a lockfile_status field:

conda workspace info --json | jq .lockfile_status

CI-friendly defaults#

When the CI environment variable is set (true, 1, or yes), conda workspace install behaves like --locked: it requires a satisfiable lockfile and fails if it is missing or out of date. This prevents accidental re-solves in CI that could produce different results than local development.

# GitHub Actions example
- run: conda workspace install  # uses lockfile, fails if out of date
  env:
    CI: true  # set by GitHub Actions automatically

To override this in CI, for example in a nightly job that refreshes the lockfile, pass --no-lock:

conda workspace install --no-lock

CI-split locking with --merge#

ci-split demo

Added in version 0.4.0: conda workspace lock --output <path> writes the solved lockfile to an arbitrary path so matrix runners can each emit one fragment. --merge <glob> stitches fragments into a single conda.lock without running the solver, validating schema version, channel lists, and rejecting overlapping (environment, platform) pairs.

Solving every platform in one job becomes expensive as a workspace grows. conda workspace lock supports matrix pipelines that split solving across runners and stitch the fragments back together on a coordinator job:

# In a matrix job, per platform
conda workspace lock --platform linux-64 --output conda.lock.linux-64
conda workspace lock --platform osx-arm64 --output conda.lock.osx-arm64
conda workspace lock --platform win-64 --output conda.lock.win-64

# On the coordinator: no solver runs, fragments are combined in place
conda workspace lock --merge "conda.lock.*"

--output writes the solved lockfile to the given path instead of the default <workspace>/conda.lock. It is required with --environment, --platform, and --skip-unsolvable, so filtered operations cannot silently replace the complete canonical lock. Each matrix runner can emit exactly one (env, platform) slice.

--merge loads every fragment, validates that they agree on schema version and on each shared environment’s channel list, and rejects overlapping (environment, platform) pairs. On success the merged conda.lock is byte-stable with what a single-run conda workspace lock would produce for the same inputs. --merge is mutually exclusive with --environment, --platform, --skip-unsolvable, and --output.

You can also select an exact manifest with the global --file / -f option:

conda workspace --file path/to/conda.toml install

The path must name a manifest file. Omit the option to auto-detect a manifest by searching the current directory and its parents.

See Lockfile management for a guided workflow that creates, installs from, and updates a lockfile.