Skip to main content
The @conda_base decorator allows you to specify Conda packages that apply to all steps in your Metaflow flow by default. Individual steps can override or augment these dependencies using @conda.

Overview

Use @conda_base to declare flow-wide Conda dependencies. This decorator sets default packages and Python versions that all steps inherit, reducing repetition in your flow definition.
from metaflow import FlowSpec, step, conda_base, conda

@conda_base(libraries={"pandas": "1.5.0", "numpy": "1.21.5"}, python=">=3.8,<3.9")
class MyFlow(FlowSpec):
    
    @step
    def start(self):
        import pandas as pd
        import numpy as np
        # Both pandas and numpy available
        self.next(self.process)
    
    @conda(libraries={"scikit-learn": "1.2.0"})
    @step
    def process(self):
        import pandas as pd
        import numpy as np
        from sklearn.ensemble import RandomForestClassifier
        # Inherits pandas and numpy, adds scikit-learn
        self.next(self.end)
    
    @step
    def end(self):
        # Also has pandas and numpy
        pass

if __name__ == "__main__":
    MyFlow()

When to Use

  • Common dependencies: When most/all steps need the same Conda packages
  • Reduce repetition: Avoid specifying the same packages on every step
  • Default Python version: Set a consistent Python version across the flow
  • Base environment: Establish a foundation that steps can extend

Parameters

libraries
Dict[str, str]
default:"{}"
Dictionary of Conda libraries to include in all steps by default. 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_base(libraries={
    "numpy": "1.21.5",
    "pandas": ">=1.4,<2.0",
    "boto3": "",
    "pytorch::pytorch": "2.0.0"
})
channels
List[str]
default:"[]"
Additional Conda channels to search for packages. By default, conda-forge is used.
@conda_base(
    libraries={"pytorch": "2.0.0"},
    channels=["pytorch", "nvidia"]
)
python
str
default:"None"
Python version constraint for all steps by default. 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_base(libraries={"pandas": "1.4.0"}, python=">=3.8,<3.9")
disabled
bool
default:"False"
If set to True, disables Conda environments for all steps by default. Individual steps can still enable Conda using @conda.
@conda_base(disabled=True)
class MyFlow(FlowSpec):
    @step
    def use_system(self):
        # Runs in system environment
        pass
    
    @conda(libraries={"pandas": "1.5.0"})
    @step
    def use_conda(self):
        # Explicitly enables Conda for this step
        pass

Deprecated Parameters

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

Usage Examples

Basic Flow-Wide Dependencies

Set common packages for all steps:
from metaflow import FlowSpec, step, conda_base

@conda_base(libraries={
    "pandas": "1.5.0",
    "numpy": "1.21.5",
    "requests": "2.28.0"
}, python=">=3.8,<3.9")
class DataPipeline(FlowSpec):
    
    @step
    def start(self):
        import pandas as pd
        import numpy as np
        import requests
        # All base packages available
        self.next(self.process)
    
    @step
    def process(self):
        import pandas as pd
        # Base packages still available
        self.next(self.end)
    
    @step
    def end(self):
        pass

Extending Base with Step-Specific Packages

Add additional packages to specific steps:
@conda_base(libraries={
    "pandas": "1.5.0",
    "numpy": "1.21.5"
})
class MLPipeline(FlowSpec):
    
    @step
    def start(self):
        import pandas as pd
        # Only base packages
        self.next(self.train, self.evaluate)
    
    @conda(libraries={"scikit-learn": "1.2.0"})
    @step
    def train(self):
        import pandas as pd
        from sklearn.ensemble import RandomForestClassifier
        # Base + scikit-learn
        self.next(self.join)
    
    @conda(libraries={"matplotlib": "3.6.0"})
    @step
    def evaluate(self):
        import pandas as pd
        import matplotlib.pyplot as plt
        # Base + matplotlib
        self.next(self.join)
    
    @step
    def join(self, inputs):
        self.next(self.end)
    
    @step
    def end(self):
        pass

Overriding Base Versions

Step-level decorators override base versions:
@conda_base(libraries={
    "pandas": "1.4.0",
    "numpy": "1.21.0"
}, python="3.8")
class VersionOverride(FlowSpec):
    
    @step
    def use_base(self):
        import pandas as pd
        # pandas 1.4.0, numpy 1.21.0, python 3.8
        self.next(self.use_override)
    
    @conda(
        libraries={"pandas": "1.5.0"},  # Overrides pandas
        python="3.9"                     # Overrides Python
    )
    @step
    def use_override(self):
        import pandas as pd
        import numpy as np
        # pandas 1.5.0 (overridden)
        # numpy 1.21.0 (inherited)
        # python 3.9 (overridden)
        self.next(self.end)
    
    @step
    def end(self):
        pass

Combining Multiple Base Decorators

Use @conda_base with @pypi_base for mixed dependencies:
from metaflow import FlowSpec, step, conda_base, pypi_base, conda

@conda_base(libraries={"numpy": "1.21.5"})
@pypi_base(packages={"requests": "2.28.0"})
class HybridFlow(FlowSpec):
    
    @step
    def start(self):
        import numpy as np
        import requests
        # Both Conda and PyPI base packages
        self.next(self.end)
    
    @conda(libraries={"pandas": "1.5.0"})
    @step
    def with_extra(self):
        import numpy as np
        import requests
        import pandas as pd
        # Base packages + pandas
        self.next(self.end)
    
    @step
    def end(self):
        pass

Disabling Conda by Default

Disable Conda for all steps except those that explicitly enable it:
@conda_base(disabled=True)
class SelectiveFlow(FlowSpec):
    
    @step
    def use_system(self):
        # Runs in system Python
        import sys
        print(sys.executable)
        self.next(self.use_conda)
    
    @conda(libraries={"pandas": "1.5.0"})
    @step
    def use_conda(self):
        # Explicitly enables Conda
        import pandas as pd
        self.next(self.end)
    
    @step
    def end(self):
        # Back to system Python
        pass

Custom Channels

Specify custom Conda channels for all steps:
@conda_base(
    libraries={
        "pytorch": "2.0.0",
        "torchvision": "0.15.0"
    },
    channels=["pytorch", "nvidia"],
    python="3.10"
)
class DeepLearningFlow(FlowSpec):
    
    @step
    def start(self):
        import torch
        print(f"PyTorch: {torch.__version__}")
        self.next(self.end)
    
    @conda(libraries={"tensorboard": "2.12.0"})
    @step
    def with_tensorboard(self):
        import torch
        import tensorboard
        # Base packages + tensorboard
        self.next(self.end)
    
    @step
    def end(self):
        pass

Merge Behavior

When combining @conda_base with step-level decorators:

Package Merging

@conda_base(libraries={"pandas": "1.4.0", "numpy": "1.21.0"})
class MergeExample(FlowSpec):
    
    @conda(libraries={"pandas": "1.5.0", "scikit-learn": "1.2.0"})
    @step
    def start(self):
        # Result:
        # - pandas: 1.5.0 (overridden by step)
        # - numpy: 1.21.0 (inherited from base)
        # - scikit-learn: 1.2.0 (added by step)
        pass

Python Version Override

@conda_base(python="3.8")
class PythonOverride(FlowSpec):
    
    @step
    def use_base_python(self):
        # Uses Python 3.8
        pass
    
    @conda(python="3.10")
    @step
    def use_different_python(self):
        # Uses Python 3.10 (overrides base)
        pass

Channel Merging

Channels from both decorators are combined:
@conda_base(channels=["conda-forge"])
class ChannelMerge(FlowSpec):
    
    @conda(
        libraries={"pytorch": "2.0.0"},
        channels=["pytorch"]
    )
    @step
    def start(self):
        # Searches both conda-forge and pytorch channels
        pass

Interaction with Other Decorators

With @pypi_base

Combine Conda and PyPI base dependencies:
@conda_base(libraries={"numpy": "1.21.5"})
@pypi_base(packages={"requests": "2.28.0"})
class DualBase(FlowSpec):
    @step
    def start(self):
        import numpy as np
        import requests
        self.next(self.end)
    
    @step
    def end(self):
        pass

With @named_env_base

Cannot combine @conda_base with @named_env_base - they are mutually exclusive:
# This will cause an error:
@conda_base(libraries={"pandas": "1.5.0"})
@named_env_base(name="team/my-env")  # ERROR: Conflicting decorators
class BadFlow(FlowSpec):
    pass
Instead, extend the named environment at the step level:
@named_env_base(name="team/base-env")
class GoodFlow(FlowSpec):
    @conda(libraries={"pandas": "1.5.0"})
    @step
    def start(self):
        # Extends the named environment
        pass

Multiple Flows in Same File

Each flow can have its own @conda_base configuration:
@conda_base(libraries={"pandas": "1.4.0"})
class FlowA(FlowSpec):
    @step
    def start(self):
        import pandas as pd
        # Uses pandas 1.4.0
        self.next(self.end)
    
    @step
    def end(self):
        pass

@conda_base(libraries={"pandas": "1.5.0"})
class FlowB(FlowSpec):
    @step
    def start(self):
        import pandas as pd
        # Uses pandas 1.5.0
        self.next(self.end)
    
    @step
    def end(self):
        pass

Requirements

  • Must use --environment=conda when running the flow
  • Requires Conda/Mamba/Micromamba installed
  • Applied at the class level (before the flow class definition)

Notes

  • Multiple @conda_base decorators are not allowed on the same flow
  • Step-level @conda always overrides conflicting @conda_base settings
  • Environments are resolved once and cached for reuse
  • Compatible with all Metaflow execution environments (local, AWS Batch, Kubernetes)

Build docs developers (and LLMs) love