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:

  1. Decrypts secrets from the ops chain
  2. Looks for .env.dev
  3. Merges overrides (local values win)
  4. 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: dev only
  • After onboarding: add staging
  • For deployments: add prod as 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