Skip to content

Environment Inheritance

Environment inheritance is Soup’s killer feature. Set values once, override where needed.

When you get a secret from an environment, Soup:

  1. Checks if the secret exists in that environment
  2. If not, checks the parent environment
  3. Continues up the chain until found or reaches the root
base (DB_HOST=localhost, DB_PORT=5432)
└── production (DB_HOST=prod-db.internal)

In this example:

  • production.DB_HOST = prod-db.internal (overridden)
  • production.DB_PORT = 5432 (inherited from base)
Terminal window
# Create the root environment
soup env create my-app base
# Create children with --parent
soup env create my-app development --parent base
soup env create my-app production --parent base

You can have multiple levels:

Terminal window
soup env create my-app base
soup env create my-app staging --parent base
soup env create my-app preview-123 --parent staging # Inherits from staging
base
└── staging
└── preview-123

preview-123 inherits from staging, which inherits from base.

The simplest and most common pattern:

Terminal window
# Create structure
soup env create api base
soup env create api dev --parent base
soup env create api staging --parent base
soup env create api prod --parent base
# Set shared config in base
soup set api base APP_NAME "My API"
soup set api base LOG_FORMAT json
soup set api base CACHE_TTL 300
# Override per environment
soup set api dev DEBUG true
soup set api prod LOG_LEVEL warn
soup set api prod CACHE_TTL 3600

For more complex setups:

Terminal window
# Create structure
soup env create api base
soup env create api nonprod --parent base
soup env create api dev --parent nonprod
soup env create api staging --parent nonprod
soup env create api prod --parent base
# Set in base
soup set api base APP_NAME "My API"
# Set in nonprod (applies to dev and staging)
soup set api nonprod DEBUG true
soup set api nonprod DB_HOST localhost
# Override for prod
soup set api prod DB_HOST prod-db.internal
base
├── nonprod
│ ├── dev
│ └── staging
└── prod

For PR preview environments:

Terminal window
# Create base structure once
soup env create api base
soup env create api staging --parent base
# For each PR, create a preview env
soup env create api preview-pr-123 --parent staging
soup set api preview-pr-123 API_URL "https://pr-123.preview.example.com"
# Clean up when PR is merged
soup env delete api preview-pr-123
5432/myapp
soup get api prod DATABASE_URL --verbose
# Output:
# Source: base (inherited)
Terminal window
soup list api prod --show-source
# Output:
# APP_NAME = My API [base]
# DB_HOST = prod-db [prod]
# DATABASE_URL = postgres://... [base]
Terminal window
soup list api prod --local
# Only shows values set directly in prod

Simply set it in the child environment:

Terminal window
# Base has LOG_LEVEL=info
soup set api prod LOG_LEVEL warn
# Now prod has LOG_LEVEL=warn, others still have info

Delete the local value to restore inheritance:

Terminal window
# prod was overriding LOG_LEVEL
soup delete api prod LOG_LEVEL
# Now prod inherits LOG_LEVEL from base again
Terminal window
soup get api prod LOG_LEVEL --verbose
# Shows if the value is local or inherited

Only put truly shared config in base:

Terminal window
# Good - same everywhere
soup set api base APP_NAME "My API"
soup set api base LOG_FORMAT json
# Bad - probably different in prod
soup set api base DATABASE_URL "postgres://localhost/mydb"

Set safe defaults in base, override for prod:

Terminal window
soup set api base DEBUG true
soup set api base LOG_LEVEL debug
soup set api base RATE_LIMIT 1000
soup set api prod DEBUG false
soup set api prod LOG_LEVEL info
soup set api prod RATE_LIMIT 100

Create a soup.md in your repo documenting your environment structure and key overrides.

Combine inheritance with variable references:

Terminal window
# Base defines the template
soup set api base DB_HOST localhost
soup set api base DB_PORT 5432
soup set api base DB_NAME myapp
soup set api base DATABASE_URL 'postgres://${DB_HOST}:${DB_PORT}/${DB_NAME}'
# Prod only overrides what's different
soup set api prod DB_HOST prod-db.internal
# DATABASE_URL automatically becomes postgres://prod-db.internal:5432/myapp