Environment Variables
Configure environment variables for your deployed applications using multiple methods.
Plain Text Values
The simplest way to set environment variables:
name: "my-app"
env:
- name: "DATABASE_URL"
value: "postgres://localhost:5432/myapp"
- name: "DEBUG"
value: "true"
- name: "MAX_CONNECTIONS"
value: "100"
name: "my-app"
env:
- name: "DATABASE_URL"
value: "postgres://localhost:5432/myapp"
- name: "DEBUG"
value: "true"
- name: "MAX_CONNECTIONS"
value: "100"
From Environment Variables
Reference environment variables from your local machine:
name: "
my-app"
env:
- name: "DATABASE_URL"
from:
env: "PRODUCTION_DATABASE_URL"
- name: "API_KEY"
from:
env: "MY_API_KEY"
- name: "SECRET_KEY"
from:
env: "APP_SECRET"
name: "
my-app"
env:
- name: "DATABASE_URL"
from:
env: "PRODUCTION_DATABASE_URL"
- name: "API_KEY"
from:
env: "MY_API_KEY"
- name: "SECRET_KEY"
from:
env: "APP_SECRET"
Set these in your shell before deploying:
export PRODUCTION_DATABASE_URL="postgres://prod-db:5432/myapp"
export MY_API_KEY="your-api-key-here"
export APP_SECRET="your-secret-here"
haloy deploy
export PRODUCTION_DATABASE_URL="postgres://prod-db:5432/myapp"
export MY_API_KEY="your-api-key-here"
export APP_SECRET="your-secret-here"
haloy deploy
Tip: You have the option to define environment variables in files which the haloy CLI tool will automatically load. See Environment Files for more details.
From Secret Providers
Use external secret management services like 1Password:
name: "my-app"
secretProviders:
onepassword:
production-db:
vault: "Production"
item: "Database Credentials"
api-keys:
vault: "API Services"
item: "Third-party APIs"
env:
- name: "DATABASE_PASSWORD"
from:
secret: "onepassword:production-db.password"
- name: "API_SECRET"
from:
secret: "onepassword:api-keys.secret-key"
- name: "STRIPE_KEY"
from:
secret: "onepassword:api-keys.stripe-key"
name: "my-app"
secretProviders:
onepassword:
production-db:
vault: "Production"
item: "Database Credentials"
api-keys:
vault: "API Services"
item: "Third-party APIs"
env:
- name: "DATABASE_PASSWORD"
from:
secret: "onepassword:production-db.password"
- name: "API_SECRET"
from:
secret: "onepassword:api-keys.secret-key"
- name: "STRIPE_KEY"
from:
secret: "onepassword:api-keys.stripe-key"
See Secret Providers for more details.
Environment Files
Haloy automatically loads environment variables from these files (in order):
.envin the current directory.env.{target}for target-specific variables.envin the Haloy config directory (~/.config/haloy/)
Example .env File
DATABASE_URL=postgres://localhost:5432/myapp
API_KEY=your-secret-api-key
DEBUG=true
MAX_CONNECTIONS=100
DATABASE_URL=postgres://localhost:5432/myapp
API_KEY=your-secret-api-key
DEBUG=true
MAX_CONNECTIONS=100
Target-Specific .env Files
For multi-target deployments:
.env.production:
DATABASE_URL=postgres://prod-db:5432/myapp
DEBUG=false
NODE_ENV=production
DATABASE_URL=postgres://prod-db:5432/myapp
DEBUG=false
NODE_ENV=production
.env.staging:
DATABASE_URL=postgres://staging-db:5432/myapp
DEBUG=true
NODE_ENV=staging
DATABASE_URL=postgres://staging-db:5432/myapp
DEBUG=true
NODE_ENV=staging
Mixed Approaches
Combine different methods in a single configuration:
name: "my-app"
env:
# Plain text for non-sensitive values
- name: "PORT"
value: "8080"
- name: "LOG_LEVEL"
value: "info"
# From environment variables
- name: "DATABASE_URL"
from:
env: "PRODUCTION_DATABASE_URL"
# From secret providers
- name: "API_SECRET"
from:
secret: "onepassword:api-keys.secret"
name: "my-app"
env:
# Plain text for non-sensitive values
- name: "PORT"
value: "8080"
- name: "LOG_LEVEL"
value: "info"
# From environment variables
- name: "DATABASE_URL"
from:
env: "PRODUCTION_DATABASE_URL"
# From secret providers
- name: "API_SECRET"
from:
secret: "onepassword:api-keys.secret"
Multi-Target Environment Variables
Merge environment variables per target:
name: "my-app"
# Base environment variables
env:
- name: "LOG_LEVEL"
value: "info"
- name: "FEATURE_FLAG"
value: "false"
targets:
production:
env: # Merges with base env
- name: "NODE_ENV"
value: "production"
- name: "LOG_LEVEL"
value: "warn" # Overrides base LOG_LEVEL
- name: "DATABASE_URL"
from:
secret: "onepassword:prod-db.url"
# Result: NODE_ENV=production, LOG_LEVEL=warn, FEATURE_FLAG=false, DATABASE_URL=<from secret>
staging:
env: # Merges with base env
- name: "NODE_ENV"
value: "staging"
- name: "LOG_LEVEL"
value: "debug" # Overrides base LOG_LEVEL
- name: "DATABASE_URL"
from:
env: "STAGING_DATABASE_URL"
# Result: NODE_ENV=staging, LOG_LEVEL=debug, FEATURE_FLAG=false, DATABASE_URL=<from env>
name: "my-app"
# Base environment variables
env:
- name: "LOG_LEVEL"
value: "info"
- name: "FEATURE_FLAG"
value: "false"
targets:
production:
env: # Merges with base env
- name: "NODE_ENV"
value: "production"
- name: "LOG_LEVEL"
value: "warn" # Overrides base LOG_LEVEL
- name: "DATABASE_URL"
from:
secret: "onepassword:prod-db.url"
# Result: NODE_ENV=production, LOG_LEVEL=warn, FEATURE_FLAG=false, DATABASE_URL=<from secret>
staging:
env: # Merges with base env
- name: "NODE_ENV"
value: "staging"
- name: "LOG_LEVEL"
value: "debug" # Overrides base LOG_LEVEL
- name: "DATABASE_URL"
from:
env: "STAGING_DATABASE_URL"
# Result: NODE_ENV=staging, LOG_LEVEL=debug, FEATURE_FLAG=false, DATABASE_URL=<from env>
Note: Environment variables defined in targets are merged with base environment variables. Target-specific values override base values with the same name, while other base values are preserved.
Best Practices
- Never commit secrets: Use
.envfiles or secret providers for sensitive data - Add .env to .gitignore: Prevent accidental commits
echo ".env" >> .gitignore
echo ".env.*" >> .gitignore
echo ".env" >> .gitignore
echo ".env.*" >> .gitignore
- Use secret providers for production: More secure than plain text or environment variables
- Document required variables: Keep a
.env.examplefile:
DATABASE_URL=postgres://localhost:5432/myapp
API_KEY=your-api-key-here
SECRET_KEY=your-secret-here
DATABASE_URL=postgres://localhost:5432/myapp
API_KEY=your-api-key-here
SECRET_KEY=your-secret-here
- Validate configuration: Use
haloy validate-configto check your setup
Viewing Resolved Configuration
To see the final configuration with all secrets resolved (use with caution):
haloy validate-config --show-resolved-config
haloy validate-config --show-resolved-config
Warning: This will display all secrets in plain text. Only use in secure environments.