Skip to main content
Conda v2 provides six decorators for specifying dependencies in your Metaflow flows. Each decorator comes in two variants: step-level and flow-level (base).

Available Decorators

@conda

Conda packages (step-level)

@conda_base

Conda packages (flow-level)

@pypi

PyPI packages (step-level)

@pypi_base

PyPI packages (flow-level)

@named_env

Named environment (step-level)

@named_env_base

Named environment (flow-level)

@conda Decorator

Specifies Conda packages for a step.

Parameters

libraries

Type: Dict[str, str]
Default: {}
Libraries to use for this step. The key is the package name and the value is the version constraint.
@conda(libraries={
    "pandas": "1.4.0",           # Exact version
    "numpy": ">=1.20,<1.24",     # Range
    "scikit-learn": "",          # Latest version
    "conda-forge::pytorch": "2.0"  # Specific channel
})
You can specify a channel for a specific package using channel::package syntax (e.g., conda-forge::pytorch).

channels

Type: List[str]
Default: []
Additional Conda channels to search for packages.
@conda(
    libraries={"pytorch": "2.0"},
    channels=["pytorch", "conda-forge"]
)

python

Type: str
Default: None (current version)
Python version constraint to use.
@conda(python="3.8.10")       # Exact version
@conda(python=">=3.8,<3.9")   # Range
@conda(python="<3.9")         # Upper bound

disabled

Type: bool
Default: False
If set to True, this step will use the external environment instead of a Conda environment.
@conda(disabled=True)
@step
def my_step(self):
    # Runs in system environment
    pass

Deprecated Parameters

These parameters are deprecated and will be removed in a future release. Use the specified alternatives instead.
  • pip_packages: Use @pypi(packages=) instead
  • pip_sources: Use @pypi(extra_indices=) instead
  • name: Use @named_env(name=) instead
  • pathspec: Use @named_env(pathspec=) instead
  • fetch_at_exec: Use @named_env(fetch_at_exec=) instead

Example

from metaflow import FlowSpec, step, conda

class MyFlow(FlowSpec):
    
    @conda(
        libraries={
            "pandas": "1.5.0",
            "numpy": ">=1.21,<1.24",
            "scikit-learn": "1.2.0"
        },
        channels=["conda-forge"],
        python=">=3.8,<3.9"
    )
    @step
    def start(self):
        import pandas as pd
        import numpy as np
        from sklearn import __version__
        print(f"pandas: {pd.__version__}")
        print(f"numpy: {np.__version__}")
        print(f"sklearn: {__version__}")
        self.next(self.end)
    
    @step
    def end(self):
        pass

if __name__ == "__main__":
    MyFlow()

@conda_base Decorator

Specifies Conda packages for all steps of the flow. Step-level @conda decorators override these settings.

Parameters

Same as @conda decorator.

Example

from metaflow import FlowSpec, step, conda, conda_base

@conda_base(
    libraries={"numpy": "1.21.5"},
    python=">=3.8,<3.9"
)
class MyFlow(FlowSpec):
    
    @step
    def start(self):
        # Uses numpy==1.21.5 from @conda_base
        import numpy as np
        print(f"numpy: {np.__version__}")
        self.next(self.process)
    
    @conda(libraries={"numpy": "1.21.6"})
    @step
    def process(self):
        # Overrides with numpy==1.21.6
        import numpy as np
        print(f"numpy: {np.__version__}")
        self.next(self.end)
    
    @conda(disabled=True)
    @step
    def end(self):
        # Runs outside conda environment
        print("System environment")

if __name__ == "__main__":
    MyFlow()

@pypi Decorator

Specifies PyPI packages for a step.

Parameters

packages

Type: Dict[str, str]
Default: {}
PyPI packages to use for this step.
@pypi(packages={
    "pandas": "1.4.0",
    "requests": ">=2.25.0",
    "mypackage": ""
})

extra_indices

Type: List[str]
Default: []
Additional PyPI index URLs to search.
@pypi(
    packages={"my-private-pkg": "1.0.0"},
    extra_indices=["https://pypi.mycompany.com/simple"]
)

python

Type: str
Default: None
Python version constraint.
@pypi(python=">=3.8,<3.9")

disabled

Type: bool
Default: False
Disable Conda environment for this step.

Example

from metaflow import FlowSpec, step, pypi

class MyFlow(FlowSpec):
    
    @pypi(
        packages={
            "pandas": "1.5.0",
            "requests": ">=2.28.0"
        },
        python=">=3.8,<3.9"
    )
    @step
    def start(self):
        import pandas as pd
        import requests
        print(f"pandas: {pd.__version__}")
        print(f"requests: {requests.__version__}")
        self.next(self.end)
    
    @step
    def end(self):
        pass

if __name__ == "__main__":
    MyFlow()

@pypi_base Decorator

Specifies PyPI packages for all steps of the flow. Step-level @pypi decorators override these settings.

Parameters

Same as @pypi decorator.

Example

from metaflow import FlowSpec, step, pypi, pypi_base

@pypi_base(
    packages={"requests": "2.28.0"},
    python=">=3.8,<3.9"
)
class MyFlow(FlowSpec):
    
    @step
    def start(self):
        # Uses requests from @pypi_base
        import requests
        print(f"requests: {requests.__version__}")
        self.next(self.end)
    
    @pypi(packages={"requests": "2.29.0"})
    @step
    def end(self):
        # Overrides with requests==2.29.0
        import requests
        print(f"requests: {requests.__version__}")

if __name__ == "__main__":
    MyFlow()

@named_env Decorator

References a named environment to use for a step.

Parameters

name

Type: str
Default: None
Name or alias of the environment to use. Can use @{} for environment variable substitution.
@named_env(name="mlp/metaflow/my_env:v1")
@named_env(name="@{MY_ENV_VAR}")

pathspec

Type: str
Default: None
Pathspec of an existing step to use its environment. Can use @{} for environment variable substitution.
@named_env(pathspec="MyFlow/123/train_step")
@named_env(pathspec="@{FLOW_NAME}/@{RUN_ID}/start")
You cannot specify both name and pathspec in the same decorator.

fetch_at_exec

Type: bool
Default: False
If True, fetches the environment when the task executes (instead of at flow start or deploy time). Useful for always using the latest version of a mutable named environment.
@named_env(
    name="mlp/metaflow/my_env:latest",
    fetch_at_exec=True
)
This is useful when you want a step to always use the latest named environment when it runs, rather than the version that was current at deploy time.

disabled

Type: bool
Default: False
Disable Conda environment for this step.

Example

from metaflow import FlowSpec, step, named_env

class MyFlow(FlowSpec):
    
    @named_env(name="mlp/metaflow/data_science_env:v1")
    @step
    def start(self):
        import numpy as np
        import pandas as pd
        print(f"Using shared environment")
        self.next(self.train)
    
    @named_env(pathspec="TrainingFlow/456/train")
    @step
    def train(self):
        # Uses the exact environment from another flow's step
        print("Training with same env as TrainingFlow")
        self.next(self.end)
    
    @step
    def end(self):
        pass

if __name__ == "__main__":
    MyFlow()

@named_env_base Decorator

References a named environment for all steps of the flow. Step-level @named_env decorators override this.

Parameters

Same as @named_env decorator.

@sys_packages Decorator

Specifies system virtual packages for a step. This is an advanced decorator for controlling the resolution environment.

Parameters

packages

Type: Dict[str, str]
Default: {}
System virtual packages to use. Supported keys are __cuda and __glibc.
@sys_packages(packages={
    "__cuda": "11.8",
    "__glibc": "2.27"
})
This is an advanced feature. Only use if you need to override default system packages for environment resolution.

disabled

Type: bool
Default: False

Example

from metaflow import FlowSpec, step, conda, sys_packages

class GPUFlow(FlowSpec):
    
    @sys_packages(packages={"__cuda": "11.8"})
    @conda(libraries={"pytorch": "2.0"})
    @step
    def train(self):
        import torch
        print(f"PyTorch version: {torch.__version__}")
        print(f"CUDA available: {torch.cuda.is_available()}")
        self.next(self.end)
    
    @step
    def end(self):
        pass

if __name__ == "__main__":
    GPUFlow()

@sys_packages_base Decorator

Specifies system virtual packages for all steps of the flow.

Parameters

Same as @sys_packages decorator.

Mixing Decorators

You can mix and match decorators on the same step:
from metaflow import FlowSpec, step, conda, pypi, named_env_base

@named_env_base(name="team/base_env:v1")
class MyFlow(FlowSpec):
    
    @conda(libraries={"numpy": "1.24.0"})
    @pypi(packages={"requests": "2.28.0"})
    @step
    def start(self):
        # Uses base_env:v1 + numpy from conda + requests from pypi
        import numpy as np
        import requests
        print(f"numpy: {np.__version__}")
        print(f"requests: {requests.__version__}")
        self.next(self.end)
    
    @step
    def end(self):
        # Uses only base_env:v1
        pass

if __name__ == "__main__":
    MyFlow()

Decorator Precedence

When multiple decorators are present:
1
Flow-level decorators are merged
2
All *_base decorators are combined. They must be compatible (e.g., same Python version).
3
Step-level decorators are merged
4
All step decorators (@conda, @pypi, @named_env, etc.) are combined.
5
Step-level overrides flow-level
6
Step-level requirements override flow-level requirements for the same packages.
If you specify python=3.7 at the flow level and python=3.8 at the step level, the step will use Python 3.8.

Environment Modes

Conda v2 supports three environment modes:
Use only @conda or @conda_base decorators:
@conda(libraries={"pandas": "1.5.0"})
Uses mamba, micromamba, or conda for resolution.

Next Steps

Resolving Environments

Learn when and how environments are resolved

Named Environments

Create reusable named environments

Build docs developers (and LLMs) love