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#
Split locking across CI runners with
--outputand--merge(see Matrix-split locking)Add Platform targeting with per-feature platform lists
Check the Lock section for all flags and error handling details