Multiple Environments
Separate your secrets by environment (dev, staging, prod) and control who has access to each.
Default Environments
When you create a project, three environments are created by default:
- dev — Local development. All team members typically have access.
- staging — Testing and QA. Mirrors production but with test data.
- prod — Production. Restricted access.
$ envctl project create myapp
✓ Created project "myapp"
Environments: dev, staging, prod
You can customize the initial environments:
$ envctl project create myapp --envs dev,qa,staging,prod
Creating Environments
Add new environments as your project grows:
$ envctl env create qa
✓ Created environment 'qa'
$ envctl env create demo
✓ Created environment 'demo'
View all environments:
$ envctl env list
Environments for myapp:
* dev (4 members)
qa (2 members)
staging (3 members)
demo (2 members)
prod (1 member)
The asterisk (*) shows your current environment.
Controlling Access
Access is granted per-environment. By default, new members only get access to dev.
Granting Access
# Grant access to staging
$ envctl project grant alice --env staging
✓ Granted alice access to staging
# Grant access to multiple environments
$ envctl project grant bob --env staging,qa
✓ Granted bob access to staging, qa
# Grant prod access (use with caution)
$ envctl project grant alice --env prod
✓ Granted alice access to prod
Revoking Access
$ envctl project revoke bob --env prod
✓ Revoked bob's access to prod
Viewing Access
$ envctl project access alice
Access for alice in myapp:
Environment Role Since
----------- ---- -----
dev member 2024-01-10
staging member 2024-01-15
qa member 2024-01-15
prod member 2024-02-01
Switching Environments
Write a .env file
$ envctl env use dev
Passphrase:
✓ .env written (5 secrets)
$ envctl env use staging
✓ .env written (5 secrets)
This decrypts secrets and writes them to .env in the current directory.
Run a command with secrets
# Run with dev secrets (default)
$ envctl env apply -- npm start
# Run with staging secrets
$ envctl env apply -e staging -- npm test
# Run with prod secrets
$ envctl env apply -e prod -- ./deploy.sh
No .env file is written—secrets exist only in memory.
Open an interactive shell
$ envctl env shell -e staging
Starting zsh with 5 secrets from myapp/staging
Type 'exit' to leave and clear secrets from memory.
$ echo $DATABASE_URL
postgres://staging-db.example.com/myapp
$ exit
Exited envctl shell. Secrets cleared.
Setting Secrets Per Environment
Each environment has its own set of secrets:
# Set in current environment
$ envctl env var set DATABASE_URL=postgres://localhost/myapp_dev
✓ Set DATABASE_URL in dev
# Set in a specific environment
$ envctl env var set -e staging DATABASE_URL=postgres://staging-db/myapp
✓ Set DATABASE_URL in staging
$ envctl env var set -e prod DATABASE_URL=postgres://prod-db/myapp
✓ Set DATABASE_URL in prod
Copying Secrets Between Environments
To copy a secret from one environment to another, you need to get and set it:
# View staging value
$ envctl env var list -e staging
STRIPE_KEY = pk_test_...
# Set same key with different value in prod
$ envctl env var set -e prod STRIPE_KEY=pk_live_...
Local Overrides
You can override shared secrets with local values using .env.<environment> files. This is useful for:
- Personal database URLs
- Debug settings
- Local service ports
Creating an Override File
Create a file named .env.dev (or .env.staging, etc.):
$ cat .env.dev
# Local overrides - not synced to team
DATABASE_URL=postgres://localhost:5433/myapp_dev
DEBUG=true
LOG_LEVEL=debug
How Overrides Work
When you run envctl env use dev, envctl:
- Decrypts secrets from the ops chain
- Looks for
.env.dev - Merges overrides (local values win)
- Writes combined result to
.env
$ envctl env use dev
✓ .env written (5 secrets)
Applied 3 override(s) from .env.dev
Ignoring Overrides
To use only the shared secrets without local overrides:
$ envctl env use dev --no-overrides
✓ .env written (5 secrets)
Git Ignore Override Files
Add override files to .gitignore:
# .gitignore
.env
.env.dev
.env.staging
.env.local
These are personal settings and shouldn't be committed.
Environment Naming Conventions
Common patterns for environment names:
| Environment | Purpose | Who Has Access |
|---|---|---|
| dev | Local development | All developers |
| test | Automated tests | All developers, CI |
| qa | QA testing | QA team, developers |
| staging | Pre-production | Senior developers, ops |
| demo | Sales demos | Sales, support |
| prod | Production | Ops, senior developers |
Deleting Environments
Remove environments you no longer need:
$ envctl env delete qa
Delete environment 'qa' and all its secrets? [y/N] y
✓ Deleted environment 'qa'
This is permanent
Deleting an environment removes all its secrets. This cannot be undone.
Best Practices
Least Privilege
Give team members access only to the environments they need:
- New developers:
devonly - After onboarding: add
staging - For deployments: add
prodas needed
Production Access
Limit production access to a small group. Most developers don't need prod secrets for daily work.
Regular Audits
Periodically review who has access:
$ envctl project members
Members of myapp:
Name Role Environments Joined
---- ---- ------------ ------
alice admin dev,staging,prod 2024-01-05
bob member dev,staging 2024-01-10
charlie member dev 2024-02-01
diana reader dev,staging,prod 2024-02-15
Use Descriptive Names
If you have multiple staging-like environments, use clear names:
$ envctl env create staging-us
$ envctl env create staging-eu
$ envctl env create staging-asia
Related
- Team Onboarding — Granting environment access to new members
- Team Offboarding — Revoking access and rotating secrets
- CI/CD Integration — Using environments in pipelines
- Command Reference: Environment commands