Skip to main content
The @conda decorator allows you to specify Conda packages required for a specific step in your Metaflow flow. This decorator augments any attributes set in the flow-level @conda_base decorator.

Overview

Use @conda to declare step-specific Conda dependencies. The decorator resolves packages from the Conda ecosystem (conda-forge by default) and creates an isolated environment for step execution.
from metaflow import FlowSpec, step, conda

class MyFlow(FlowSpec):
    
    @conda(libraries={"pandas": "1.4.0"}, python=">=3.8,<3.9")
    @step
    def start(self):
        import pandas as pd
        print(f"Pandas version: {pd.__version__}")
        self.next(self.end)
    
    @step
    def end(self):
        print("Done!")

if __name__ == "__main__":
    MyFlow()
Run with:
python myflow.py --environment=conda run

When to Use

  • Step-level dependencies: When only specific steps need certain Conda packages
  • Version overrides: Override flow-level versions from @conda_base for specific steps
  • Mixed dependencies: Combine with @pypi for hybrid Conda/PyPI environments
  • Different versions: Use different package versions across steps

Parameters

libraries
Dict[str, str]
default:"{}"
Dictionary of Conda libraries to include. Keys are package names, values are version constraints.Version constraints can be:
  • Simple pinned versions: "1.2.3"
  • Range constraints: ">=4.0,<6.0"
  • Channel-specific: "conda-forge::package"
  • Empty string for floating versions: ""
@conda(libraries={
    "numpy": "1.21.5",           # Exact version
    "pandas": ">=1.4,<2.0",      # Range
    "scikit-learn": "",          # Latest available
    "pytorch::pytorch": "2.0.0"  # From specific channel
})
channels
List[str]
default:"[]"
Additional Conda channels to search for packages. By default, conda-forge is used.
@conda(
    libraries={"pytorch": "2.0.0"},
    channels=["pytorch", "nvidia"]
)
python
str
default:"None"
Python version constraint for the environment. If not specified, the current Python version is used.Can be a specific version or a constraint expression:
  • "3.8.12" - Exact version
  • ">=3.8,<3.9" - Range constraint
  • "<3.11" - Upper bound only
@conda(libraries={"pandas": "1.4.0"}, python=">=3.8,<3.9")
disabled
bool
default:"False"
If set to True, disables the Conda environment for this step and uses the external environment instead.
@conda(disabled=True)
@step
def use_system_env(self):
    # Runs in system Python, not Conda environment
    pass

Deprecated Parameters

pip_packages
Dict[str, str]
default:"{}"
DEPRECATED - Use @pypi(packages=...) instead.Dictionary of PyPI packages. Superseded by the dedicated @pypi decorator.
pip_sources
List[str]
default:"[]"
DEPRECATED - Use @pypi(extra_indices=...) instead.Additional PyPI package sources. Use @pypi decorator instead.
name
str
default:"None"
DEPRECATED - Use @named_env(name=...) instead.Reference to a named environment. Superseded by @named_env decorator.
pathspec
str
default:"None"
DEPRECATED - Use @named_env(pathspec=...) instead.Reference to a pathspec of an existing step. Use @named_env decorator instead.
fetch_at_exec
bool
default:"False"
DEPRECATED - Use @named_env(fetch_at_exec=...) instead.Fetch environment at execution time. Use @named_env decorator instead.

Usage Examples

Basic Usage

Specify a simple Conda dependency:
from metaflow import FlowSpec, step, conda

class SimpleFlow(FlowSpec):
    
    @conda(libraries={"numpy": "1.21.5"})
    @step
    def start(self):
        import numpy as np
        print(f"NumPy version: {np.__version__}")
        self.next(self.end)
    
    @step
    def end(self):
        pass

if __name__ == "__main__":
    SimpleFlow()

Multiple Packages with Version Constraints

@conda(libraries={
    "pandas": ">=1.4,<2.0",
    "numpy": "1.21.5",
    "scikit-learn": ">=1.0"
}, python=">=3.8,<3.9")
@step
df analysis(self):
    import pandas as pd
    import numpy as np
    from sklearn.ensemble import RandomForestClassifier
    # Your ML code here
    self.next(self.end)

Different Versions Across Steps

Test compatibility with multiple package versions:
class CompatibilityTest(FlowSpec):
    
    @conda(libraries={"pandas": "1.4.0"}, python=">=3.8,<3.9")
    @step
    def test_pandas_v1(self):
        import pandas as pd
        assert pd.__version__ == "1.4.0"
        self.next(self.test_pandas_v2)
    
    @conda(libraries={"pandas": "1.5.0"}, python=">=3.8,<3.9")
    @step
    def test_pandas_v2(self):
        import pandas as pd
        assert pd.__version__ == "1.5.0"
        self.next(self.end)
    
    @step
    def end(self):
        print("All tests passed!")

Using Custom Channels

@conda(
    libraries={"pytorch": "2.0.0", "torchvision": "0.15.0"},
    channels=["pytorch", "nvidia"],
    python="3.10"
)
@step
def train_model(self):
    import torch
    print(f"PyTorch version: {torch.__version__}")
    print(f"CUDA available: {torch.cuda.is_available()}")
    self.next(self.end)

Combining with Flow-Level Decorator

Override base dependencies with step-specific versions:
from metaflow import FlowSpec, step, conda, conda_base

@conda_base(libraries={"numpy": "1.21.0"}, python=">=3.8,<3.9")
class MyFlow(FlowSpec):
    
    @step
    def use_base(self):
        import numpy as np
        # Uses numpy 1.21.0 from @conda_base
        self.next(self.use_override)
    
    @conda(libraries={"numpy": "1.22.0"})
    @step
    def use_override(self):
        import numpy as np
        # Uses numpy 1.22.0 (overrides base)
        assert np.__version__ == "1.22.0"
        self.next(self.end)
    
    @step
    def end(self):
        pass

Disabling Conda for Specific Steps

@conda_base(libraries={"pandas": "1.5.0"})
class MixedFlow(FlowSpec):
    
    @step
    def with_conda(self):
        import pandas as pd
        # Runs in Conda environment
        self.next(self.without_conda)
    
    @conda(disabled=True)
    @step
    def without_conda(self):
        # Runs in system environment
        # Good for steps that need system-level tools
        import subprocess
        subprocess.run(["some-system-command"])
        self.next(self.end)
    
    @step
    def end(self):
        pass

Interaction with Other Decorators

With @pypi

Combine Conda and PyPI packages for mixed dependencies:
from metaflow import FlowSpec, step, conda, pypi

class HybridFlow(FlowSpec):
    
    @conda(libraries={"numpy": "1.21.5"})
    @pypi(packages={"requests": "2.28.0"})
    @step
    def start(self):
        import numpy as np
        import requests
        # Use both Conda and PyPI packages
        self.next(self.end)
    
    @step
    def end(self):
        pass

With @named_env

Extend a named environment with additional packages:
@named_env(name="team/base-ml-env:v1")
@conda(libraries={"xgboost": "1.7.0"})
@step
def train(self):
    # Uses base-ml-env plus xgboost
    import xgboost as xgb
    self.next(self.end)

Merge Behavior

When combining @conda with @conda_base:
  1. Step-level overrides flow-level: Package versions in @conda override those in @conda_base
  2. Python version is overridden: Step-level python parameter overrides flow-level
  3. Channels are merged: Channels from both decorators are combined
  4. Disabled takes precedence: Setting disabled=True at step level disables Conda entirely
@conda_base(
    libraries={"pandas": "1.4.0", "numpy": "1.21.0"},
    python="3.8"
)
class MergeExample(FlowSpec):
    
    @conda(
        libraries={"pandas": "1.5.0"},  # Overrides pandas version
        python="3.9"                     # Overrides Python version
    )
    @step
    def start(self):
        import pandas as pd
        import numpy as np
        # pandas: 1.5.0 (overridden)
        # numpy: 1.21.0 (inherited from base)
        # python: 3.9 (overridden)
        self.next(self.end)
    
    @step
    def end(self):
        pass

Environment Resolution

Environments are resolved:
  1. Locally: On the machine launching the flow
  2. Before execution: Prior to flow run or deployment
  3. Cached: Resolved environments are cached in S3/GS/Azure
  4. Shared: Cached environments are reused across runs
Force re-resolution:
python myflow.py --environment=conda environment resolve --force

Requirements

  • Must use --environment=conda when running the flow
  • Requires Conda/Mamba/Micromamba installed
  • Remote execution (AWS Batch, Kubernetes) automatically handles environment creation

Notes

  • Environments are hermetic and reproducible
  • All transitive dependencies are locked for reproducibility
  • Environments are reused when requirements don’t change
  • Compatible with remote execution (AWS Batch, Kubernetes)
  • Can mix with PyPI packages using @pypi decorator

Build docs developers (and LLMs) love