Skip to main content
Named environments in Conda v2 work like Docker tags - they provide human-readable aliases for fully resolved environments, making it easy to share and version your dependency configurations.

What Are Named Environments?

A named environment is an alias for a fully resolved environment. Instead of referring to an environment by its 40-character hexadecimal hash, you can use a memorable name like mlp/metaflow/data_science_env:v1.
Named environments are similar to Docker image tags. Just as python:3.9 points to a specific Docker image, my_team/my_env:v1 points to a specific resolved Conda environment.

Alias Format

Aliases follow a recommended naming convention:
team/project/environment_name:tag
  • Hierarchical structure: Use / to organize by team, project, or purpose
  • Optional tag: Use : followed by a version tag (e.g., :v1, :latest, :stable)
  • Default tag: If no tag is specified, :latest is assumed

Examples

mlp/metaflow/conda_example/numpy_test_env:v1
data_science/training/pytorch_env:stable
team_name/project/ml_env:latest
my_environment
  • mlp/metaflow/data_science:v1 - Full path with version
  • my_team/my_env - Defaults to :latest tag
  • simple_env:v2 - Simple name with version
  • test_environment - Simplest form (defaults to :latest)

Immutability Rules

Aliases are immutable by default, with important exceptions:
Most tags are immutable - once set, they cannot be changed:
my_team/my_env:v1      # Immutable
my_team/my_env:v2      # Immutable
my_team/my_env:prod    # Immutable
This ensures reproducibility. If someone references :v1, they always get the exact same environment.
Once you alias an environment with an immutable tag, you cannot change that alias to point to a different environment. You must use a new tag (e.g., :v2 instead of :v1).

Creating Named Environments

There are several ways to create named environments:

From Requirements File

Resolve and alias an environment from a requirements file:
metaflow environment resolve \
  --python ">=3.8,<3.9" \
  --alias mlp/metaflow/conda_example/numpy_test_env:v1 \
  -r requirements.txt

From Environment File

Resolve and alias from an environment.yml file:
metaflow environment resolve \
  --python ">=3.8,<3.9" \
  --alias my_team/my_project/env:v1 \
  -f environment.yml

From Flow

Resolve all environments in a flow and alias one:
python myflow.py --environment=conda environment resolve \
  --alias my_team/my_flow_env:v1

Aliasing Existing Environment

Alias an environment that’s already resolved:
metaflow environment alias \
  42a4ed94b63f12e1fe9dd29de21bf9ec6e271b1c \
  my_team/my_env:v1
Or alias from a pathspec:
metaflow environment alias \
  --pathspec MyFlow/123/train \
  my_team/training_env:v2

Using Named Environments

Once you’ve created a named environment, use it in your flows:

With @named_env Decorator

from metaflow import FlowSpec, step, named_env

class MyFlow(FlowSpec):
    
    @named_env(name="mlp/metaflow/conda_example/numpy_test_env:v1")
    @step
    def start(self):
        import numpy as np
        print(f"numpy version: {np.__version__}")
        assert np.__version__ == "1.21.5"
        self.next(self.end)
    
    @step
    def end(self):
        pass

if __name__ == "__main__":
    MyFlow()

With Environment Variable Substitution

Use environment variables in environment names:
@named_env(name="@{TEAM}/my_project/@{ENV_NAME}:@{VERSION}")
@step
def my_step(self):
    # Environment name is constructed from:
    # TEAM, ENV_NAME, and VERSION environment variables
    pass
export TEAM="mlp"
export ENV_NAME="training_env"
export VERSION="v2"
python myflow.py --environment=conda run

With fetch_at_exec

For mutable tags, fetch the latest version at execution time:
@named_env(
    name="my_team/my_env:latest",
    fetch_at_exec=True
)
@step
def my_step(self):
    # Always uses the current :latest environment
    # when this step executes (not when flow is deployed)
    pass
fetch_at_exec=True is useful for development environments that should always use the latest packages, but be cautious in production as it can affect reproducibility.

Pathspecs as Aliases

You can reference any previously executed step’s environment using its pathspec:
@named_env(pathspec="TrainingFlow/456/train")
@step
def inference(self):
    # Uses the exact environment from TrainingFlow/456/train
    pass
Pathspecs are automatically treated as aliases:
# Show environment for a pathspec
metaflow environment show --pathspec MyFlow/123/train

# Create local environment from pathspec
metaflow environment create --pathspec MyFlow/123/train --name my_env

Extending Named Environments

You can create a new environment by extending an existing named environment with additional dependencies:

Using —using Option

Extend an environment while maintaining all its locked dependencies:
env_extra.yml
dependencies:
  - itsdangerous=2.1.2
metaflow environment resolve \
  --using mlp/metaflow/conda_example/numpy_test_env:v1 \
  --alias mlp/metaflow/conda_example/numpy_danger_env:v1 \
  -f env_extra.yml
This creates a new environment that:
  • Includes all packages from numpy_test_env:v1 with locked versions
  • Adds itsdangerous=2.1.2
  • Gets a new alias numpy_danger_env:v1
Extending does not modify the original environment. It creates a new environment. All locked dependencies from the base environment are preserved - you cannot add incompatible packages.

Using —using-pathspec Option

Extend from a pathspec:
metaflow environment resolve \
  --using-pathspec MyFlow/123/train \
  --alias my_team/extended_env:v1 \
  -r additional_requirements.txt

Cloning Environments

Use --from or --from-pathspec to clone requirements (not locked versions):
metaflow environment resolve \
  --from mlp/metaflow/my_env:v1 \
  --alias mlp/metaflow/my_env_linux:v1 \
  --arch linux-64
This resolves the same requirements for a different architecture, but may result in different package versions.

Sharing Named Environments

Named environments are automatically shared when cached to S3/Azure/GCS:
1
Create and Resolve
2
One team member resolves and aliases an environment:
3
metaflow environment resolve \
  --alias data_science/shared_env:v1 \
  -r requirements.txt
4
Automatic Caching
5
The environment and all packages are cached to cloud storage.
6
Use by Others
7
Other team members can use the environment immediately:
8
@named_env(name="data_science/shared_env:v1")
@step
def my_step(self):
    # Automatically downloads environment if not local
    pass
9
Explicit Fetch
10
Or explicitly fetch the environment:
11
metaflow environment get data_science/shared_env:v1

Listing and Inspecting Named Environments

Show Environment Details

metaflow environment show my_team/my_env:v1
Output:
DEFAULT Environment of type conda-only full hash d49465b2b45996e40aad1f3aaf00cba553a0f085:f671c941b27764ad6536f7fdadc6c57b18221c6e
Aliases mlp/metaflow/conda_example/numpy_test_env:latest (mutable)
Arch linux-64
Available on linux-64

Resolved on 2023-09-06 07:16:01.794427
Resolved by romain

Locally present as /usr/local/libexec/metaflow-condav2-20230809/envs/metaflow_d49465b2b45996e40aad1f3aaf00cba553a0f085_f671c941b27764ad6536f7fdadc6c57b18221c6e

User-requested packages conda::boto3==>=1.14.0, conda::numpy==1.21.5, conda::pandas==>=0.24.0, ...
User sources conda::conda-forge

Conda Packages installed _libgcc_mutex==0.1-conda_forge, numpy==1.21.5, pandas==2.0.3, ...

Get Environment

Fetch and optionally set as default:
metaflow environment get my_team/my_env:v1
Skip setting as default:
metaflow environment get --no-default my_team/my_env:v1

Managing Named Environment Versions

A recommended versioning strategy:

Development Workflow

1
Use :candidate for Testing
2
metaflow environment resolve \
  --alias my_team/my_env:candidate \
  -r requirements.txt
3
Test with the candidate environment:
4
@named_env(name="my_team/my_env:candidate")
5
Promote to :stable
6
metaflow environment alias my_team/my_env:candidate my_team/my_env:stable
7
Create Versioned Release
8
metaflow environment alias my_team/my_env:stable my_team/my_env:v1
9
Update :latest
10
metaflow environment alias my_team/my_env:v1 my_team/my_env:latest

Production Workflow

Best practice: Use immutable version tags (:v1, :v2) in production flows to ensure reproducibility. Use mutable tags (:latest, :stable) only in development or when you explicitly want rolling updates.
# Development: uses latest
@named_env(
    name="my_team/my_env:latest",
    fetch_at_exec=True
)

# Production: uses pinned version
@named_env(name="my_team/my_env:v1")

Example Workflow

Here’s a complete example of creating and using named environments:

1. Create Requirements

requirements.txt
pandas==1.5.0
numpy>=1.21,<1.24
scikit-learn==1.2.0

2. Resolve and Alias

metaflow environment resolve \
  --python ">=3.8,<3.9" \
  --alias ml_team/training/sklearn_env:v1 \
  -r requirements.txt

3. Use in Flow

from metaflow import FlowSpec, step, named_env

class TrainingFlow(FlowSpec):
    
    @named_env(name="ml_team/training/sklearn_env:v1")
    @step
    def train(self):
        from sklearn.ensemble import RandomForestClassifier
        import pandas as pd
        import numpy as np
        
        print("Training with:")
        print(f"  pandas: {pd.__version__}")
        print(f"  numpy: {np.__version__}")
        
        # Your training code here
        self.next(self.end)
    
    @step
    def end(self):
        pass

if __name__ == "__main__":
    TrainingFlow()

4. Share with Team

Team members can now use the same environment:
class InferenceFlow(FlowSpec):
    
    @named_env(name="ml_team/training/sklearn_env:v1")
    @step
    def predict(self):
        # Uses exact same environment as training
        pass

Next Steps

CLI Reference

Learn all environment CLI commands

Configuration

Configure environment caching and sharing

Build docs developers (and LLMs) love