Multi-platform locking#

This tutorial walks through locking a workspace for multiple platforms so that teammates on Linux, macOS, and Windows all get reproducible environments from the same conda.lock.

Prerequisites#

  • conda (>= 24.7) with conda-workspaces >= 0.4.0 installed

  • An existing workspace with a conda.toml (see Your first project if you need one)

Declare your platforms#

If you are starting a new project, pass --platform (repeatable) to workspace init:

conda workspace init --platform linux-64 --platform osx-arm64 --platform win-64

Or if you already have a conda.toml, edit the platforms list directly:

[workspace]
name = "my-project"
channels = ["conda-forge"]
platforms = ["linux-64", "osx-arm64", "win-64"]

[dependencies]
python = ">=3.11"
numpy = ">=1.26"

If you omit --platform during init, only your current platform is added. The platforms list tells the lock command which subdirs to solve for.

Add a platform to an existing workspace#

There is no dedicated CLI command to add a platform after the fact. Edit the platforms array in your conda.toml directly:

[workspace]
platforms = ["linux-64", "osx-arm64", "win-64"]  # added win-64

Then re-lock to generate solutions for the new platform:

conda workspace lock

If you only want to solve the newly added platform (faster for large workspaces), target it explicitly:

conda workspace lock --platform win-64

This writes a lockfile covering just win-64. To fold it into your existing conda.lock that already covers the other platforms, use --output and --merge:

conda workspace lock --platform win-64 --output conda.lock.win-64
conda workspace lock --merge "conda.lock.*"

Or simply re-run conda workspace lock without flags to regenerate the full lockfile from scratch.

Generate the lockfile#

Run conda workspace lock from the project root:

conda workspace lock

This solves every environment for every declared platform and writes a single conda.lock. On a macOS ARM machine it will solve for linux-64 and win-64 in addition to osx-arm64, using conda’s virtual package overrides to target the correct subdir.

The output looks something like:

Locking default for linux-64...
Locking default for osx-arm64...
Locking default for win-64...
Wrote conda.lock (3 environments × 3 platforms)

Lock a subset of platforms#

If you only need to refresh one platform (for example, after adding a Linux-only dependency), pass --platform:

conda workspace lock --platform linux-64

This flag is repeatable:

conda workspace lock --platform linux-64 --platform osx-arm64

Unknown platforms (typos like lnux-64) are rejected before the solver runs.

Add platform-specific dependencies#

Some packages only exist on certain platforms. Use [target] tables:

[target.linux-64.dependencies]
linux-headers = ">=5.10"

[target.osx-arm64.dependencies]
llvm-openmp = ">=14.0"

Re-run conda workspace lock and only the affected platforms pick up the new packages.

Pin system requirements#

When cross-solving (for example, generating a linux-64 lock from macOS), the solver needs to know target system constraints. Use the [system-requirements] table:

[system-requirements]
glibc = "2.17"

This adds __glibc >=2.17 as a virtual package constraint for Linux solves. Without it the solver may pick packages that require a newer glibc than your deployment target.

You can also pin via environment variables for one-off overrides:

CONDA_OVERRIDE_GLIBC=2.17 conda workspace lock --platform linux-64

Handle unsolvable platforms#

Some combinations of dependencies are unsolvable on certain platforms (a package might not be built for win-64 yet). By default the lock command fails on the first broken solve. To keep going and lock what you can:

conda workspace lock --skip-unsolvable

This prints a yellow Skipping ... line for each failed (environment, platform) pair and writes the lockfile with the successful solves. If every pair fails, no lockfile is written and the command exits with an error.

Install from the lockfile#

On any machine, install the exact locked versions without re-solving:

conda workspace install --locked

This validates that the lockfile is still fresh relative to the manifest. If you’ve changed conda.toml since locking, the install fails and asks you to re-lock. To skip that check:

conda workspace install --frozen

Verify the platform set#

To see which platforms are reachable (workspace-level plus any feature-level additions):

conda workspace info

The text output shows a “Known Platforms” row when features expand beyond the workspace default. The JSON form exposes this as known_platforms:

conda workspace info --json | jq .known_platforms

Next steps#

  • Split locking across CI runners with --output and --merge (see CI pipeline)

  • Add features with per-feature platform lists

  • Check the Lock section for all flags and error handling details