conda.toml specification#
This page is the normative reference for the conda.toml workspace
manifest format read by conda-workspaces. It is the human-readable
companion to schema/conda-toml-1.schema.json and the source
material for the future Conda Enhancement Proposal that will
standardise the format across the conda ecosystem.
For tutorials and examples see Configuration and Quickstart. For plugin name aliases see Plugin format names and aliases.
Status#
Field |
Value |
|---|---|
Format name |
|
Schema version |
|
Schema URL |
|
Canonical plugin name |
|
Reference implementation |
|
Standardisation track |
Pre-CEP — see the CEP tracker issue |
Scope#
conda.toml describes a workspace: a project root that may declare
one or more conda environments composed from reusable features, plus
a set of tasks that run inside those environments. It is the
conda-native sibling of pixi.toml. The core workspace, dependency,
feature, environment, and task tables deliberately overlap with pixi,
while conda-workspaces also owns conda-specific extensions such as
default-environment and [workspace.archive]. The reverse direction
(pixi.toml → conda.toml) holds only when the pixi.toml keeps to the
fields described here. See Pixi compatibility ladder below for the
precise asymmetry.
Out of scope: package build recipes (use recipe.yaml), package
distribution metadata (pyproject.toml [project]), and lockfile
contents (use the companion conda.lock, see Lockfile relationship
below).
File detection#
A conda-workspaces tool MUST detect a workspace using one of these two forms, in order:
A file named
conda.tomlat the workspace root that contains a top-level[workspace]table.A file named
pyproject.tomlat the workspace root that contains a[tool.conda.workspace]table.
A conda.toml without a [workspace] table is permitted: it is
treated as a tasks-only manifest (see [tasks] below) and does not
constitute a workspace on its own.
For compatibility, conda-workspaces also reads pixi.toml (top-level
[workspace] / [project]) and pyproject.toml
[tool.pixi.workspace]. That compatibility surface is not part of
this specification — it is documented in
Configuration.
Search order#
Tools that search a directory tree for the manifest MUST consult these filenames in this order, returning the first hit:
conda.tomlpixi.tomlpyproject.toml
When more than one form is present in the same directory, conda.toml
wins. When pyproject.toml contains both [tool.conda] and
[tool.pixi] tables, [tool.conda] wins (see
Configuration).
Top-level tables#
All tables are optional unless marked required. Field types follow TOML conventions: string, integer, boolean, array, table, inline-table.
[workspace] (required when used as a workspace manifest)#
Workspace metadata.
Field |
Type |
Required |
Description |
|---|---|---|---|
|
string |
no |
Workspace name. Defaults to the workspace directory name. |
|
string |
no |
Workspace version. |
|
string |
no |
Short prose description. |
|
array of channel |
yes |
Conda channels in priority order. |
|
array of platform |
yes |
Platforms the workspace targets. Used to drive multi-platform solves. |
|
string |
no |
One of |
|
string |
no |
Where per-env prefixes live, relative to the workspace root. Default: |
|
conda deps |
no |
Root-level dependency pool used by |
|
table |
no |
Archive filters and compression settings. See |
A channel is either:
a string containing a channel name (
"conda-forge") or URL ("https://my.channel/label/dev"), oran inline table
{ channel = "<name-or-url>" }. Other keys (e.g.priority) are reserved and currently ignored by this version.
A platform is either a conda subdir string from the closed enum
defined in the JSON schema under $defs.platform (e.g.
linux-64, osx-arm64, win-64, noarch) or a Pixi-compatible
rich-platform inline table. Rich-platform tables may set
platform = "<subdir>", an optional workspace-scoped name, and
virtual package constraints such as cuda, archspec, glibc /
libc, linux, macos / osx, windows / win, or raw
__<virtual-package> keys.
[workspace]
platforms = [
"linux-64",
{ name = "linux-64-cuda", platform = "linux-64", cuda = "12.0" },
]
When name is omitted, conda-workspaces follows Pixi’s
generated-name style, for example
{ platform = "linux-64", cuda = "12.0" } becomes
linux-64-cuda-12-0. The declared name is used by feature
platforms restrictions and as the conda.lock platform key. The
backing platform subdir is used for conda solves and package URL
validation.
[workspace.archive]#
Archive settings used by conda workspace archive.
Field |
Type |
Description |
|---|---|---|
|
array of string |
Glob patterns for files to include. When set, only matching files are archived. |
|
array of string |
Glob patterns for files to exclude. |
|
string |
One of |
|
integer |
Compression level passed to the selected compressor. |
[workspace.dependencies]#
Reusable conda package specs keyed by package name. Regular dependency
tables can opt into a root spec with { workspace = true }, which keeps
shared versions in one place while preserving explicit package membership
in each feature or target table. This follows the workspace dependency
inheritance syntax that pixi added in 0.70.0.
[workspace.dependencies]
numpy = "1.*"
cmake = { version = ">=3.28", channel = "conda-forge" }
[dependencies]
python = ">=3.12"
numpy = { workspace = true }
[feature.build.dependencies]
cmake = { workspace = true, build = "h*" }
The inherited entry uses the root spec as a base. Non-version fields such
as build, channel, subdir, md5, sha256, url, file-name,
license, license-family, features, and track-features may be
set on the consuming dependency to layer on top. version is owned by
the workspace entry. Setting both workspace = true and version is an
error. workspace = false is also rejected.
[dependencies]#
Conda packages that belong to the default feature. Keys are package
names. Values are either a version constraint string or a detailed
dependency spec. Detailed specs may also inherit from
[workspace.dependencies] with { workspace = true }.
[dependencies]
python = ">=3.10"
numpy = ">=1.24,<2"
scipy = "*"
cuda-toolkit = { version = ">=12", build = "*cuda*" }
A detailed conda dependency accepts:
Field |
Type |
Description |
|---|---|---|
|
string |
Version constraint (e.g. |
|
string |
Build-string glob (e.g. |
|
string |
Build number constraint. |
|
string |
Channel name or URL for this package. |
|
platform |
Platform/subdir constraint. |
|
string |
Exact package hash. |
|
string |
Exact package URL. |
|
string |
Exact package filename. |
|
string |
License constraints. |
|
array of strings |
Feature constraints. |
|
boolean |
Must be |
[pypi-dependencies]#
PyPI packages that belong to the default feature. Keys are package names. Values are either a PEP 508 version-constraint string or a detailed PyPI dependency spec:
Field |
Type |
Description |
|---|---|---|
|
string |
PEP 508 constraint. |
|
array of string |
Extras to request, e.g. |
|
string |
Local path to the package. |
|
boolean |
Install in editable mode. |
|
string |
Git repository URL. |
|
string |
Branch (with |
|
string |
Tag (with |
|
string |
Revision (with |
|
string |
Direct package URL. |
[activation]#
Default-feature activation settings.
Field |
Type |
Description |
|---|---|---|
|
array of string |
Shell scripts sourced on environment activation. |
|
table of |
Environment variables set on activation. |
[system-requirements]#
Default-feature system-level constraints (e.g. minimum glibc, macOS
version). Recognised keys mirror conda’s virtual-package names
(__glibc, __osx, __cuda, …). Values are stringified version
constraints, except libc may also use pixi’s inline table form
{ family = "glibc", version = "2.28" }.
[target.<platform>]#
Per-platform overrides for the default feature. <platform> may be
a declared platform name or the backing conda subdir of a declared rich
platform. When both match, the subdir target is merged first and the
declared rich-platform name can override it.
Field |
Type |
Description |
|---|---|---|
|
conda deps |
Platform-specific conda overrides. |
|
PyPI deps |
Platform-specific PyPI overrides. |
[feature.<name>]#
A reusable group of dependencies and settings. <name> is an
arbitrary identifier referenced from [environments].
Field |
Type |
Description |
|---|---|---|
|
conda deps |
Conda dependencies for this feature. |
|
PyPI deps |
PyPI dependencies for this feature. |
|
array of channel |
Additional channels. |
|
array of string |
Restrict the feature to declared platform names or subdirs. |
|
table |
Per-feature system requirements. |
|
table |
Per-feature activation. |
|
table of |
Per-platform dep overrides for the feature. |
|
table |
Tasks contributed by this feature and merged into the workspace task set. |
[environments]#
A named environment is a composition of one or more features plus
(by default) the default feature defined by the top-level
[dependencies], [pypi-dependencies], [activation] and
[system-requirements] tables.
Two forms are accepted:
[environments]
test = ["test"] # shorthand
docs = { features = ["docs"], no-default-feature = false }
Field |
Type |
Description |
|---|---|---|
|
array of string |
Feature names to include in addition to the default feature. |
|
string |
Accepted for pixi compatibility. Currently ignored. Environments are solved independently. |
|
boolean |
If |
When [environments] is omitted entirely, a single implicit
environment named default is used, composed from the default feature
only.
[tasks]#
Named tasks runnable via conda task run <name>. Each value is
either a command string or a task table.
Field |
Type |
Description |
|---|---|---|
|
string or array of string |
Command to execute. Omit to define an alias whose only purpose is |
|
array of task arg |
Named arguments with optional defaults. |
|
array of task dep |
Tasks to run before this one. |
|
string |
Working directory for the task. |
|
table of |
Environment variables to set. |
|
string |
Human-readable description. |
|
array of string |
Glob patterns for cache inputs. |
|
array of string |
Glob patterns for cache outputs. |
|
boolean |
Run with a minimal environment. |
|
string |
Conda environment to activate by default for this task. |
|
table of |
Per-platform overrides. |
A task arg is an inline table such as
{ arg = "path", default = "tests/" }.
A task dep is one of:
a string naming another task:
"build", oran inline table with extra fields:
{ task = "test", args = ["tests/unit/"], environment = "py311" }.
[target.<platform>.tasks]#
Platform-specific task overrides. Each entry follows the same shape
as a [tasks] entry.
Composition rules#
When a tool resolves an environment named <env>:
Start with the default feature (top-level
[dependencies],[pypi-dependencies],[activation],[system-requirements],[target]) unless the environment setsno-default-feature = true.Merge in each named feature listed in
features, in order. Later features override earlier ones for conflicting keys. Lists are concatenated and de-duplicated.Apply
[target.<platform>]overrides for the host’s platform last.
Channel order is preserved. Duplicate dependency names within the same stack (conda or PyPI) are an error and the tool MUST surface them to the user.
Lockfile relationship#
conda workspace lock and conda workspace install produce and
consume conda.lock at the workspace root. The lockfile schema is
derived from rattler-lock v6 (the same schema
pixi.lock uses) with one on-disk difference: conda.lock writes
version: 1 instead of version: 6 so tools can identify the file as
conda-workspaces-owned at a glance. The remainder of the document —
environments, packages, channels, platform package lists — is
structure-compatible with rattler-lock v6.
See Plugin format names and aliases for the
canonical and alias strings under which conda.lock is registered.
Lockfile satisfiability check#
conda workspace install and conda workspace info evaluate the
lockfile against the manifest to determine whether a re-solve is
needed. The check is purely structural (no file timestamps) and
runs in this order:
Schema version – the lockfile
versionfield must match the expected version (1).Environments – every environment declared in the manifest must have a corresponding entry in the lockfile.
Channels – the channel list for each environment in the lockfile must match the manifest (order-sensitive, URLs normalized).
Platforms – every platform declared in the manifest must be present in each lockfile environment’s
packagessection.Dependencies – for each dependency in the manifest (on the current platform), a locked package must exist whose version satisfies the manifest’s version spec.
The check returns the first failing condition it finds. The result is one of three states:
Status |
Constant |
Meaning |
|---|---|---|
|
|
All checks pass |
|
|
At least one check fails |
|
|
No |
JSON output fields#
conda workspace info --json includes the following lockfile fields:
Field |
Type |
Description |
|---|---|---|
|
|
One of |
|
|
Human-readable reason (only present when |
Embedded form (pyproject.toml)#
The same tables are accepted under [tool.conda.<name>] inside a
pyproject.toml:
Top-level table |
Embedded equivalent |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
When both conda.toml and pyproject.toml exist in the same
directory, conda.toml wins. When a pyproject.toml contains both
[tool.conda] and [tool.pixi] tables, [tool.conda] wins.
Pixi compatibility ladder#
conda.toml and pixi.toml share a deliberately overlapping table
layout, but they are not byte-for-byte interchangeable. The
relationship is:
Direction |
Holds? |
Why |
|---|---|---|
Every valid |
No |
The core workspace/dependency/task fields overlap intentionally, but conda-workspaces extensions such as |
Every valid |
No |
Pixi’s |
pixi reads our |
No |
|
conda-workspaces reads |
Yes |
conda-workspaces ships a separate compatibility reader for |
Two intentional differences from pixi.toml:
conda.tomlaccepts only[workspace]. The legacy pixi[project]table is not part of this specification.conda-workspaces resolves dependencies with conda’s configured solver backend and installs them as conventional conda prefixes. Pixi’s build-process options (e.g.
[package]-style build recipes) are not part of this specification.
If you need pixi-only fields, write a pixi.toml and let
conda-workspaces’ compatibility reader handle it. Do not extend
conda.toml with them.
Versioning policy#
The schema is versioned with a single integer (1). A future
backwards-incompatible change to required fields, semantics, or
defaults bumps the version to 2 and gets a sibling schema URL
(https://schemas.conda.org/conda-toml-2.schema.json) and plugin
canonical name (conda-workspaces-v2). Aliases follow the rules in
format-aliases.md.
Backwards-compatible additions (new optional fields, new platforms in the platform enum) do not bump the version. The JSON schema is the strict validation target for this version. The conda-workspaces runtime parser is intentionally more permissive for pixi and forward compatibility and may ignore unknown fields when reading manifests.
Open questions (non-normative)#
These are tracked for the CEP draft and are not part of v1:
Whether
[workspace]should be required to carryversionandname(currently both optional).Whether
solve-groupshould ever gain conda-workspaces semantics, or remain an accepted no-op compatibility field.Whether to standardise an
[envs]shorthand that maps a feature one-to-one to an environment of the same name.Discovery rules for nested workspaces (currently parent-directory search stops at the first match).
Whether
[tool.pixi.*]compatibility belongs in this specification or in a separate “compatibility” CEP.Whether
conda.tomlshould exist as a separate filename at all, or whether the spec should describe a “conda-workspaces dialect ofpixi.toml” — i.e. apixi.tomlplus conda-workspaces extensions such asdefault-environmentand[workspace.archive], without a parallel filename or schema URL. Trade-off: governance ownership (conda community vs. Prefix.dev) versus format proliferation. See the CEP tracker for discussion.