Multi-platform locking#

Lock a workspace for multiple platforms so teammates on Linux, macOS, and Windows can reproduce their environments from the same conda.lock.

Prerequisites#

  • conda (>= 26.3) with conda-workspaces >= 0.8.0 installed

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

Declare your platforms#

If you are creating a workspace, pass --platform (repeatable) to workspace init:

conda workspace init -c conda-forge --override-channels \
  --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.

Change workspace platforms#

To add a platform after creating the workspace, run:

conda workspace platform add win-64

This updates the workspace’s platforms array and conda.lock. Existing solutions are retained, and only newly required targets are solved. If there is no lockfile yet, the command generates one for the complete workspace. If an existing lockfile is stale, run conda workspace lock first.

Preview removing Windows support, then apply the change:

conda workspace platform remove win-64 --dry-run
conda workspace platform remove win-64

These commands change the platforms of environments that inherit the workspace list. Explicit feature platform lists are unchanged. Installed environments are unchanged. Use --no-lockfile-update to edit the manifest and lock later.

Removing the last workspace platform leaves platforms = [], which makes inheriting environments use the native platform. To keep a portable lockfile, retain the concrete platforms your teammates need.

Change a feature’s platforms#

A feature can declare its own platform list. For example, add a tools feature and an environment that uses it to your manifest:

[feature.tools]
platforms = ["osx-arm64"]

[feature.tools.dependencies]
ruff = "*"

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

Generate a current lockfile, then add Linux support to this feature:

conda workspace lock
conda workspace platform add --feature tools linux-64

The second command edits [feature.tools].platforms and solves the newly needed lock targets. It retains the existing solutions and leaves installed environments unchanged. Every environment that includes tools sees the updated platform list.

Preview removing Linux support before making the change:

conda workspace platform remove --feature tools linux-64 --dry-run
conda workspace platform remove --feature tools linux-64

If you remove the last explicit platform, environments that use the feature derive their supported platforms from their other features or the workspace. The command explains this in its output. Use --no-lockfile-update to edit only the manifest and lock later. See Platform management for all options.

Generate the lockfile#

Run conda workspace lock from the workspace 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.

Example output:

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 --output conda.lock.linux-64

This flag is repeatable:

conda workspace lock --platform linux-64 --platform osx-arm64 \
  --output conda.lock.unix

Unknown platforms (typos like lnux-64) are rejected before the solver runs. The explicit output keeps a partial result from replacing the complete canonical lock.

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 \
  --output conda.lock.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 --output conda.lock.solvable

This prints a yellow Skipping ... line for each failed (environment, platform) pair and writes the successful solves to the explicit fragment. 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#