Skip to content

Environment Precedence

Environment Precedence

Environment variables are resolved with a clear precedence order, ensuring predictable behavior when the same variable is defined in multiple locations.

Source: Implementation in src/cook/environment/manager.rs:95-137

Precedence Order

Environment variables are applied in the following order (later sources override earlier ones):

  1. Parent environment - Inherited from the parent process
  2. Environment files - Loaded from env_files (later files override earlier)
  3. Global env - Defined at workflow level in YAML
  4. Active profile - Applied if a profile is set (internal infrastructure)
  5. Step-specific env - Per-step environment variables
  6. Secrets - Loaded from secrets configuration (applied after step env)
  7. Shell-level overrides - Using ENV=value command syntax

Source: Precedence implementation in src/cook/environment/manager.rs:95-137

Implementation Details

Parent Environment Inheritance

By default, workflows inherit all environment variables from the parent process. You can disable this with inherit: false in the environment configuration.

# Disable parent environment inheritance
inherit: false

env:
  # Only these variables will be available
  NODE_ENV: production

Source: Parent environment loading at src/cook/environment/manager.rs:98-102

Environment Files Precedence

When multiple environment files are specified, later files override earlier ones. This allows layering of configuration (base + environment-specific).

env_files:
  - .env              # Base configuration
  - .env.production   # Overrides base values

Source: Environment file loading at src/cook/environment/manager.rs:107-109

Global Environment

The global env block at the workflow level overrides both parent environment and environment files.

env:
  NODE_ENV: production  # Overrides .env files and parent environment
  API_URL: https://api.example.com

Source: Global environment application at src/cook/environment/manager.rs:112-115

Profile Infrastructure

Prodigy includes internal profile infrastructure that can activate different environment configurations. However, this feature is not currently exposed via CLI flags.

# Profile infrastructure exists but no --profile CLI flag available
profiles:
  development:
    NODE_ENV: development
    API_URL: http://localhost:3000

Source: Profile application at src/cook/environment/manager.rs:118-120; No CLI flag in src/cli/args.rs

Step-Specific Environment

Note: The YAML command syntax (WorkflowStepCommand) does not expose step-level environment configuration. However, the internal runtime (StepEnvironment) supports it for future extensibility.

Source: - StepEnvironment struct at src/cook/environment/config.rs:128-144 - Step environment application at src/cook/environment/manager.rs:123-127

Secrets Loading

Secrets are loaded AFTER step-specific environment variables, ensuring they cannot be accidentally overridden by step configuration.

secrets:
  API_KEY: "${env:SECRET_API_KEY}"

# This takes precedence over global env, env_files, and step env

Source: Secrets application at src/cook/environment/manager.rs:130-137

Shell-Level Overrides

Shell syntax provides the highest precedence override, applied at command execution time.

- shell: "NODE_ENV=test echo $NODE_ENV"  # Prints: test

This override is handled by the shell itself and takes precedence over all Prodigy environment sources.

Complete Example

Here's a comprehensive example demonstrating all precedence levels:

# Parent environment: NODE_ENV=local (inherited by default)

env_files:
  - .env  # Contains: NODE_ENV=development, API_URL=http://localhost:3000

env:
  NODE_ENV: production      # Overrides .env file and parent
  API_URL: https://api.prod.example.com  # Overrides .env file

secrets:
  API_KEY: "${env:SECRET_API_KEY}"  # Loaded after global env

commands:
  - shell: "echo $NODE_ENV"          # Prints: production (from global env)
  - shell: "echo $API_URL"           # Prints: https://api.prod.example.com
  - shell: "echo $API_KEY"           # Prints: *** (masked, from secrets)

  # Override using shell syntax (highest precedence)
  - shell: "NODE_ENV=staging echo $NODE_ENV"  # Prints: staging

Source: Real-world example from workflows/environment-example.yml

Precedence Resolution Flow

When resolving an environment variable, Prodigy follows this flow:

1. Start with parent environment (if inherit: true, default)
2. Apply each env_file in order (later files override)
3. Apply global env block (overrides files and parent)
4. Apply active profile if set (internal feature)
5. Apply step-specific env (runtime capability)
6. Apply secrets (highest Prodigy-level precedence)
7. Shell overrides apply at execution time (highest overall)

Result: The last value set wins, creating a predictable override chain.

Debugging Precedence Issues

When troubleshooting which environment source is active:

# Print all environment variables to debug precedence
- shell: "env | sort"
  capture_output: true

# Print specific variable to verify its value
- shell: "echo NODE_ENV=$NODE_ENV"

Common debugging scenarios: - Variable not set: Check if parent environment is being inherited - Wrong value: Check which precedence level last set the variable - Secrets not working: Verify secrets are loaded after step environment - Override not applying: Ensure shell syntax is correct