SecurityNovember 18, 20257 min read

Managing API Keys Across Dev, Staging, and Production

Different API keys for every environment, scattered across machines and .env files. Here's how to organize and sync them without the chaos.

The Problem: Key Sprawl Across Environments

A typical web application talks to a dozen external services: Stripe for payments, SendGrid for email, AWS for storage, Twilio for SMS, Sentry for error tracking. Each of these has separate API keys for development, staging, and production. Multiply a dozen services by three environments and you are managing 36 secrets — at minimum.

These keys end up in .env files scattered across machines. Your laptop has dev keys. The staging server has staging keys. Production credentials live on the deploy server and maybe in a password manager somewhere. When you set up a new machine, you spend an hour hunting down the right keys for the right environment, copying them from various sources, and hoping you did not accidentally paste the production Stripe key into your development environment.

Common Mistakes That Lead to Incidents

Using the same key for dev and prod. It seems convenient until your local test suite charges a real credit card, sends a real email to a real customer, or deletes production data. Using the same key across environments eliminates the safety net that separate environments are supposed to provide.

Committing keys to git. Even in a private repository, committed secrets are accessible to everyone with clone access and persist in git history forever. A single git push with a .env file can expose every API key in the project.

Sharing keys in Slack or email. "Hey, can someone send me the staging Stripe key?" is a message that will live in your company's Slack retention logs indefinitely. Those messages are searchable, exportable, and accessible to workspace admins. It is the equivalent of writing your passwords on a whiteboard in a shared office.

The root cause is always the same: there is no single, secure, environment-aware system for managing API keys. Developers improvise, and improvisation leads to leaks.

ConfigSync Environments: Scoped Secrets

ConfigSync introduces environments as a first-class concept. Each environment is an isolated scope for secrets, with its own encryption and access controls. When you push or pull, ConfigSync uses the active environment to determine which secrets to sync.

Create environments
# Create your environments $ configsync env create development --tier dev Created environment "development" (tier: dev) $ configsync env create staging --tier staging Created environment "staging" (tier: staging) $ configsync env create production --tier production --protect Created environment "production" (tier: production, protected) # Protected environments require confirmation before overwriting
Switch between environments
# Set your active environment $ configsync env use development Active environment: development # Check which environment is active $ configsync env status Active: development (tier: dev) Available: development, staging, production

Environment-Scoped .env Files

When you add and push .env files, they are stored under the active environment's scope. Pulling on a machine with a different active environment retrieves that environment's secrets instead.

Push dev secrets from your laptop
# On your laptop, with "development" active $ configsync env use development $ configsync add env ~/git/myapp $ configsync push --filter env Encrypting .env files (environment: development)... ✓ ~/git/myapp/.env (12 variables, AES-256-GCM) ✓ ~/git/myapp/.env.local (3 variables, AES-256-GCM) Pushed 2 env files to "development" scope.
Push staging secrets from the staging server
# On the staging server, with "staging" active $ configsync env use staging $ configsync push --filter env Encrypting .env files (environment: staging)... ✓ ~/git/myapp/.env (12 variables, AES-256-GCM) Pushed 1 env file to "staging" scope.

Now when you pull on any machine, ConfigSync checks the active environment and delivers the correct secrets:

Pull respects the active environment
# On a new dev machine $ configsync env use development $ configsync pull --filter env Restored 2 env files from "development" scope. # On a new staging machine $ configsync env use staging $ configsync pull --filter env Restored 1 env file from "staging" scope.

Secret Providers for Extra Security

For teams that want an additional layer of security, ConfigSync integrates with external secret providers. Instead of storing encrypted secrets in ConfigSync's cloud vault, secrets can live in your team's existing password manager.

Use 1Password for team secrets
# Configure 1Password as the secret provider $ configsync config set secrets.provider 1password $ configsync config set secrets.1password.vault "Engineering" # Push stores secrets in your 1Password vault $ configsync push --filter env Pushed 2 env files to 1Password vault "Engineering". # Team members pull from the same vault $ configsync pull --filter env Pulled 2 env files from 1Password vault "Engineering".
Bitwarden for self-hosted teams
# Configure Bitwarden $ configsync config set secrets.provider bitwarden $ configsync config set secrets.bitwarden.server "https://vault.company.com" # Works the same way $ configsync push --filter env $ configsync pull --filter env

inject_as_env: Secrets That Never Touch Disk

The most secure secret is one that never exists as a file. ConfigSync's inject_as_env mode loads secrets directly into a process's environment without writing a .env file to disk. This eliminates the risk of secrets being included in backups, read by other processes, or accidentally committed.

Inject secrets into your dev server
# Run your app with injected secrets — no .env file created $ configsync inject --project myapp --env development -- npm run dev Injecting 15 environment variables (development)... > next dev ready - started server on 0.0.0.0:3000 # Secrets exist only in the process's memory. # When the process exits, the secrets are gone.
With inject_as_env, there is no .env file to accidentally commit, no file for malware to read, and no plaintext secret stored anywhere on the filesystem. Secrets go from the encrypted vault directly into your running process.

A Complete Workflow for API Key Management

Here is the full workflow for managing API keys across environments with ConfigSync:

  1. Create environments: configsync env create development, staging, production.
  2. Add .env files on each environment's machine: configsync add env ~/git/myapp.
  3. Push from each environment: configsync push --filter env.
  4. On new machines, set the environment and pull: configsync env use development && configsync pull.
  5. For maximum security, use configsync inject instead of writing .env files.

No more hunting for keys in Slack threads. No more "which .env file goes with which server?" confusion. No more accidentally using production keys in development. Each environment's secrets are isolated, encrypted, and available exactly where they need to be.

Ready to try ConfigSync?

Sync your entire dev environment across machines in minutes. Free forever for up to 3 devices.