Coming from conda#

If you manage environments with conda create, conda activate, and environment.yml files, this guide shows how conda-workspaces brings project-scoped environments, lockfiles, and tasks to the workflow you already know.

What stays the same#

conda-workspaces is a conda plugin — it uses conda’s configured solver backend, channels, and package infrastructure under the hood. Your .condarc settings, channel configuration, and package cache all carry over. Environments are real conda prefixes you can inspect with conda list.

What changes#

Traditional conda

conda-workspaces

Environments live in a global location

Environments live in .conda/envs/ inside your project

One environment per environment.yml

Multiple environments from a single manifest

No lockfile (or separate conda-lock)

conda.lock generated automatically

No built-in task runner

conda task run with dependencies, caching, templates

conda activate myenv

conda workspace shell -e myenv

Share environment.yml and hope it resolves

Share conda.lock for exact reproducibility

Command mapping#

conda

conda-workspaces

conda create -n myenv python=3.10

conda workspace init + conda workspace add -e myenv python=3.10

conda activate myenv

conda workspace shell -e myenv

conda deactivate

exit

conda install numpy

conda workspace add numpy (edits the manifest and installs)

conda update numpy

conda workspace update numpy (preserves the declared constraint)

conda remove numpy

conda workspace remove numpy (edits the manifest and uninstalls)

conda list

conda workspace list

conda run -n myenv CMD

conda workspace run -e myenv -- CMD

conda env export > environment.yml

conda workspace export -e myenv --from-prefix --file environment.yml

Migrating an environment.yml#

environment import demo

Create a workspace from environment.yml#

To create a workspace from one environment.yml, run the import command without -e/--environment:

conda workspace import environment.yml

This reads your environment.yml and writes a conda.toml with the equivalent workspace configuration. Use --dry-run to preview the output without writing a file, or -o custom.toml to choose a different output path. This form converts the complete source manifest. It does not merge with an existing workspace, update conda.lock, or install an environment. The global --file option is not accepted in this mode.

The importer preserves representable conda channel, build, subdir, hash, and credential-free direct URL fields, along with PyPI extras. It rejects embedded credentials in direct package sources, PyPI direct URLs, and environment markers instead of silently changing their meaning. Keep PyPI direct sources in the source manifest until the importer can represent them losslessly. Replace platform markers with [target.<platform>.pypi-dependencies] declarations when applicable.

For reference, given an existing environment.yml:

name: my-project
channels:
  - conda-forge
dependencies:
  - python>=3.10
  - numpy>=1.24
  - pandas>=2.0
  - pip:
    - requests>=2.31

On a linux-64 machine, the equivalent conda.toml is:

[workspace]
name = "my-project"
channels = ["conda-forge"]
platforms = ["linux-64"]

[dependencies]
python = ">=3.10"
numpy = ">=1.24"
pandas = ">=2.0"

[pypi-dependencies]
requests = ">=2.31"

Then install:

conda workspace install

Add environment.yml to an existing workspace#

To add a complete environment.yml as a new named workspace environment, pass the target name with -e/--environment:

conda workspace import -e data environment.yml

The command adds private conda dependencies under [environments.data.dependencies] and private PyPI dependencies under [environments.data.pypi-dependencies]. The environment does not inherit the workspace’s default dependencies. The command-line name is authoritative, so a different name: in the YAML does not rename the workspace environment. The target name must be new and cannot be default.

Named import accepts only environment.yml and environment.yaml. To select an exact target manifest, put the global --file option before import:

conda workspace --file path/to/pixi.toml import -e data environment.yml

If the YAML omits channels or platforms, the imported environment uses the workspace values. If it declares channels, they must match the workspace channels in the same credential-safe normalized order. Declared platforms must match the workspace’s declared platform names. Channels, platforms, channel priority, and rich-platform requirements remain workspace settings. The nodefaults channel marker cannot be represented by a named workspace environment and must be removed before import.

A YAML prefix: is ignored with a warning because workspace environments live under .conda/envs/. Named import rejects variables: and unknown top-level keys instead of dropping configuration it cannot represent.

By default, named import refreshes the complete lockfile and installs the new environment. Use these options to control that lifecycle:

Option

Result

No lifecycle option

Update the manifest and complete lockfile, then install the new environment

--no-install

Update the manifest and complete lockfile without changing a prefix

--no-lockfile-update

Update only the manifest

--force-reinstall

Replace an existing inactive target prefix after validation

--dry-run

Parse, validate, and solve without writing the manifest, lockfile, or prefix

An existing target prefix requires --force-reinstall. The active prefix cannot be replaced. --force-reinstall cannot be combined with --no-install or --no-lockfile-update.

Lockfiles: reproducibility built in#

Traditional conda has no built-in lockfile. You might use conda env export to capture a snapshot, but the output is platform-specific and re-solving from it can produce different results over time.

conda-workspaces generates a conda.lock file automatically when you run conda workspace install or conda workspace lock. The lockfile records exact package URLs and checksums for every environment and platform in your workspace:

conda workspace lock                   # solve only, write conda.lock
conda workspace install                # solve, lock, and install
conda workspace install --locked       # install from lockfile (validates freshness)
conda workspace install --frozen       # install from lockfile (skip freshness check)

--locked ensures the lockfile matches your manifest — if you’ve changed dependencies since the lockfile was generated, the install fails and tells you to re-lock. --frozen skips that check and installs exactly what’s in the lockfile, which is useful in CI where you want zero solver overhead.

Commit conda.lock to version control and every contributor, CI runner, and deployment target gets identical environments.

Works with conda env create#

conda-workspaces registers environment spec plugins so that standard conda commands understand workspace manifests and lockfiles directly:

conda env create --file conda.toml -n myenv    # solve and create from manifest
conda env create --file conda.lock -n myenv    # install exact lockfile contents

This means you can share a conda.toml or conda.lock with someone who has conda-workspaces installed and they can create an environment with the familiar conda env create command — no new workflow to learn.

The conda.lock loader used by conda env create rejects external package references because that interface cannot carry their verified artifacts into conda’s installer. Declare external dependencies in conda.toml, regenerate conda.lock, then use conda workspace install.

The companion conda-lockfiles plugin (installed as a dependency) adds the same conda env create support for pixi.lock and conda-lock.yml files. Together the two plugins cover all common lockfile formats:

Plugin

Files

Format

conda-workspaces

conda.toml

workspace manifest

conda-workspaces

conda.lock

rattler-lock-derived, version: 1

conda-lockfiles

pixi.lock

rattler-lock v6

conda-lockfiles

conda-lock.yml

conda-lock v1

Multiple environments from one manifest#

With traditional conda you create separate environments and manage them individually. conda-workspaces lets you define composable features in a single file:

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

[dependencies]
python = ">=3.10"
numpy = ">=1.24"

[feature.test.dependencies]
pytest = ">=8.0"

[feature.docs.dependencies]
sphinx = ">=7.0"

[environments]
default = []
test = { features = ["test"] }
docs = { features = ["docs"] }

One conda workspace install creates all three environments, each with the right subset of dependencies. Features compose — the test environment includes everything in default plus pytest.

Adding tasks#

Traditional conda has no task runner, so most projects use Makefiles, shell scripts, or tox. conda-workspaces has tasks built in:

[tasks]
test = { cmd = "pytest tests/ -v", depends-on = ["lint"] }
lint = "ruff check src/"

[tasks.check]
depends-on = ["test", "lint"]
description = "Run all checks"
conda task run -e test check    # resolves dependency order automatically
conda task list                 # shows all available tasks

Tasks support dependency graphs, input/output caching, Jinja2 templates, and per-platform overrides — see features for details.

Project-local environments#

Traditional conda stores environments globally (typically under ~/miniconda3/envs/). conda-workspaces stores them inside your project:

my-project/
├── conda.toml
├── conda.lock
└── .conda/envs/
    ├── default/
    ├── test/
    └── docs/

This keeps your project self-contained. Different projects can have different versions of the same packages without conflicting.

Next steps#