Manage Secrets Across Environments
Create, scope, sync, and compare secrets across your deployment environments
Secrets are sensitive values — API keys, database credentials, tokens — that your services need at runtime but should never be committed to source control. Hostess provides a built-in secret store that encrypts and manages these values across all your environments.
In your hostess.yml, secrets are referenced using the ${secret:NAME} syntax:
services:
backend:
type: fastapi
build:
source: ./backend
env:
JWT_SECRET: ${secret:JWT_SECRET}
STRIPE_KEY: ${secret:STRIPE_API_KEY}
SENDGRID_API_KEY: ${secret:SENDGRID_API_KEY}This guide covers how to create, manage, sync, and compare secrets using the Hostess CLI.
Creating Secrets
From an environment variable
export API_KEY="sk_test_abc123"
hostess secrets add API_KEY✓ Secret 'API_KEY' added to productionWhen --value is omitted, hostess secrets add <name> reads the value from a local environment variable with the same name. If neither --value nor $NAME is set, the command fails instead of prompting interactively.
Inline value
In CI/CD, interpolate the value from a CI secret environment variable rather than hardcoding it:
hostess secrets add STRIPE_KEY --value "$STRIPE_KEY"Using --value can store the secret in your shell history. Prefer exporting the value from a password manager or CI secret first, then let the CLI read $SECRET_NAME:
export STRIPE_KEY="$STRIPE_KEY_FROM_PASSWORD_MANAGER"
hostess secrets add STRIPE_KEYCreating multiple secrets at once
Add several secrets in quick succession:
export JWT_SECRET="$(openssl rand -base64 32)"
hostess secrets add JWT_SECRET
hostess secrets add STRIPE_KEY --value sk_live_abc123
export SENDGRID_API_KEY="SG.abc123"
hostess secrets add SENDGRID_API_KEY
hostess secrets add SENTRY_DSN --value https://abc123@sentry.io/456Environment Scoping
By default, a secret is available in all environments. You can scope a secret to specific environments using the --envs flag:
# Available in production only
hostess secrets add STRIPE_LIVE_KEY --envs production --value sk_live_abc123
# Available in both staging and production
hostess secrets add DATABASE_PASSWORD --envs production,staging --value "$DATABASE_PASSWORD"
# Available in preview environments only
hostess secrets add TEST_API_KEY --envs preview --value sk_test_xyz789Why scope secrets?
Scoping prevents test keys from leaking into production and production keys from appearing in preview environments:
| Secret | Production | Staging | Preview |
|---|---|---|---|
STRIPE_LIVE_KEY | sk_live_... | - | - |
STRIPE_TEST_KEY | - | sk_test_... | sk_test_... |
JWT_SECRET | prod-jwt-... | staging-jwt-... | preview-jwt-... |
SENTRY_DSN | https://... | https://... | - |
To set different values per environment, create the same secret name with different scopes:
# Production Stripe key
hostess secrets add STRIPE_KEY --envs production --value sk_live_abc123
# Staging and preview use test key
hostess secrets add STRIPE_KEY --envs staging,preview --value sk_test_xyz789Syncing with Local .env Files
Hostess can sync secrets between your local .env files and the remote secret store. This is useful for keeping local development aligned with deployed environments.
Push local secrets to Hostess
Upload all secrets from a local .env file to a specific environment:
hostess secrets sync push --env production --file .env.productionThis reads your .env.production file and creates or updates each key-value pair as a secret scoped to the production environment.
Example .env.production file:
JWT_SECRET=super-secret-production-key
STRIPE_KEY=sk_live_abc123xyz
SENDGRID_API_KEY=SG.abc123
DATABASE_URL=postgresql://user:pass@host:5432/dbhostess secrets sync push --env production --file .env.production
Sync Summary:
------------------------------
Added: 4
Updated: 0
Unchanged: 0
------------------------------
Total: 4 secrets syncedPull remote secrets to local
Download secrets from a Hostess environment to a local file:
hostess secrets sync pull --env productionThis creates or overwrites a .env file with the current secret values from the specified environment.
You can also specify a custom output file:
hostess secrets sync pull --env staging --file .env.stagingNever commit .env files to version control. Make sure your .gitignore includes:
.env
.env.*Comparing Secrets Across Environments
The diff command shows which secrets exist in each environment and highlights differences:
hostess secrets diff production staging
Secret Diff: production vs staging
==================================================
Only in production (1):
- SENDGRID_API_KEY = SG.***123
Only in staging (1):
+ TEST_MODE = ***
Different values (1):
JWT_SECRET:
production: pro***ret
staging: sta***ret
Identical (1):
= SENTRY_DSNThis is especially useful before promoting staging to production, to ensure all required secrets are present.
Editing and Rotating Secrets
Update an existing secret
To change a secret's value, use hostess secrets edit. The add command skips environments where that secret already exists and tells you to use edit instead.
export JWT_SECRET="$(openssl rand -base64 32)"
hostess secrets edit JWT_SECRET✓ Secret 'JWT_SECRET' updated in production
✓ Secret 'JWT_SECRET' updated in stagingRotation workflow
When rotating a secret (e.g., after a key compromise or on a regular schedule):
Update the secret value
hostess secrets edit STRIPE_KEY --envs production --value sk_live_new_keyRedeploy to apply
Secrets are injected at deploy time. After updating a secret, redeploy the affected services:
hostess deployOr deploy only the services that use the rotated secret:
hostess deploy -s backend -s workerVerify the service is running with the new value
Check your deployment status in Studio or via the CLI:
hostess deployments listUpdating a secret does not automatically redeploy your services. You must trigger a new deployment for the updated value to take effect.
Listing Secrets
View all secrets for your project:
hostess secrets getEnvironment: production
--------------------------------------------------
KEY | VALUE
----------------------
JWT_SECRET | pro***ret
STRIPE_KEY | sk_***xyz
Environment: staging
--------------------------------------------------
KEY | VALUE
---------------------------
JWT_SECRET | sta***ret
STRIPE_TEST_KEY | sk_***789By default, secret values are masked in the CLI. Use hostess secrets get --show-values when you need to reveal values (treat output like a password).
Deleting Secrets
Remove a secret that is no longer needed:
hostess secrets delete OLD_API_KEY✓ Secret 'OLD_API_KEY' deleted from production
✓ Secret 'OLD_API_KEY' deleted from stagingDeleting a secret that is still referenced in hostess.yml will cause your next deployment to fail. Remove the ${secret:NAME} reference from your configuration before deleting the secret.
Referencing Secrets in hostess.yml
Secrets are referenced in environment variables using the ${secret:NAME} syntax:
services:
backend:
type: fastapi
build:
source: ./backend
env:
# Secret references
JWT_SECRET: ${secret:JWT_SECRET}
STRIPE_KEY: ${secret:STRIPE_KEY}
SENDGRID_API_KEY: ${secret:SENDGRID_API_KEY}
# Regular environment variables (not secrets)
LOG_LEVEL: info
NODE_ENV: production
# Magic variables (service discovery, not secrets)
DATABASE_URL: ${database.url}
REDIS_URL: ${cache.url}If a referenced secret does not exist in the Hostess secret store, the deployment will fail with a clear error message telling you which secret is missing.
Best Practices
Naming conventions
Use consistent, uppercase naming with underscores:
| Good | Bad |
|---|---|
STRIPE_API_KEY | stripe-api-key |
DATABASE_PASSWORD | dbPassword |
SENDGRID_API_KEY | SendGrid_Key |
JWT_SIGNING_SECRET | jwt |
Prefix secrets by service or provider for clarity:
STRIPE_API_KEY
STRIPE_WEBHOOK_SECRET
SENDGRID_API_KEY
SENDGRID_TEMPLATE_ID
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
SENTRY_DSNRotation schedule
Set up a regular rotation schedule for sensitive credentials:
| Secret Type | Recommended Rotation |
|---|---|
| API keys (third-party) | Every 90 days |
| JWT signing secrets | Every 90 days |
| Database passwords | Every 180 days |
| Webhook secrets | When compromised |
| OAuth client secrets | Every 90 days |
Environment separation
- Never share production API keys with preview or staging environments
- Use test/sandbox keys from third-party services for non-production environments
- Scope secrets to the minimum number of environments they need
Do not duplicate database URLs
Hostess automatically provides database connection URLs via magic variables like ${database.url}. Do not store database URLs as secrets — use magic variables instead:
services:
backend:
env:
# Correct — use magic variable
DATABASE_URL: ${database.url}
# Incorrect — do not store as a secret
# DATABASE_URL: ${secret:DATABASE_URL}