Coming from conda-project#
conda-project and conda-workspaces both provide project-scoped conda environments. If you are migrating from conda-project, this guide maps the concepts and commands to their conda-workspaces equivalents.
Key differences#
Aspect |
conda-project |
conda-workspaces |
|---|---|---|
Manifest |
|
single |
Lockfile |
|
|
Environment location |
|
|
Multiple environments |
separate |
composable features in one manifest |
Commands |
flat |
|
Variables |
|
Jinja2 templates + environment variables |
Solver |
conda / conda-lock |
configured conda solver backend |
pixi compatibility |
no |
reads |
Platform overrides |
per-platform lock only |
per-platform dependencies and tasks |
Command mapping#
conda-project |
conda-workspaces |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Automatic conversion#
Use the built-in import command to convert your manifest:
conda workspace import conda-project.yml
This reads your conda-project.yml (and the environment.yml files
it references) and writes a single conda.toml with all dependencies,
environments, and commands converted. Use --dry-run to preview the
output, or -o custom.toml to choose a different output path.
Migrating the manifest#
A typical conda-project setup has two files:
# conda-project.yml
name: my-project
environments:
default:
- environment.yml
variables:
DATABASE_URL:
commands:
test: pytest tests/ -v
serve: python -m http.server
# environment.yml
name: my-project
channels:
- conda-forge
dependencies:
- python>=3.10
- numpy>=1.24
- pip:
- requests
The equivalent single conda.toml:
[workspace]
name = "my-project"
channels = ["conda-forge"]
platforms = ["linux-64", "osx-arm64"]
[dependencies]
python = ">=3.10"
numpy = ">=1.24"
[pypi-dependencies]
requests = "*"
[tasks]
test = "pytest tests/ -v"
serve = "python -m http.server"
Multiple environments#
conda-project uses separate environment.yml files for each
environment, referenced from conda-project.yml:
# conda-project.yml
environments:
default:
- environment.yml
dev:
- environment.yml
- dev-extras.yml
Imported environment files must be referenced with project-local relative paths. References that resolve outside the project directory are rejected.
conda-workspaces uses composable features instead:
[dependencies]
python = ">=3.10"
numpy = ">=1.24"
[feature.dev.dependencies]
pytest = ">=8.0"
ruff = ">=0.4"
[environments]
default = []
dev = { features = ["dev"] }
Features compose automatically — dev inherits all base dependencies
and adds its own. No need for separate files or duplicate entries.
Variables and environment#
conda-project has a variables: block with optional defaults and
.env file support:
variables:
FOO: has-default-value
BAR:
conda-workspaces uses Jinja2 templates in task commands and standard environment variables:
[tasks]
deploy = "deploy --env {{ env.DEPLOY_TARGET | default('staging') }}"
For simple cases, set variables in your shell or .env file before
running tasks.
Commands to tasks#
conda-project commands are flat name-to-command mappings. conda-workspaces tasks add dependency resolution, caching, and descriptions:
# conda-project.yml
commands:
test: pytest tests/ -v
lint: ruff check src/
# conda.toml
[tasks]
test = { cmd = "pytest tests/ -v", depends-on = ["lint"] }
lint = "ruff check src/"
[tasks.check]
depends-on = ["test", "lint"]
description = "Run all checks"
Running conda task run check automatically resolves the dependency
graph and runs lint before test.
Lockfiles#
conda-project generated separate conda-lock.<env>.yml files using
conda-lock. conda-workspaces generates a single conda.lock that
uses a rattler-lock-derived schema and covers all environments and
platforms:
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)
conda-workspaces registers environment spec plugins so that standard conda commands understand both workspace manifests and lockfiles:
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
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 other lockfile formats. If you still have conda-lock.yml
files from conda-project, they work too:
conda env create --file conda-lock.yml -n myenv # via conda-lockfiles plugin
Plugin |
Files |
Format |
|---|---|---|
conda-workspaces |
|
workspace manifest |
conda-workspaces |
|
rattler-lock-derived, |
conda-lockfiles |
|
rattler-lock v6 |
conda-lockfiles |
|
conda-lock v1 |
What’s new in conda-workspaces#
Beyond what conda-project offered, conda-workspaces adds:
Task dependency graphs with topological ordering
Input/output caching for tasks (skip unchanged work)
Jinja2 templates in task commands
Per-platform task and dependency overrides
pixi manifest compatibility (
pixi.tomlandpyproject.toml)A single lockfile covering all environments and platforms
Standalone CLIs (
cw/ct) alongside the conda plugin
Next steps#
Your first project — full walkthrough
Coming from pixi — if you also use pixi
Features — environments, tasks, caching, templates