How to Manage SaaS Environment Variables Across Staging and Production
Environment variables are the configuration layer of your SaaS: database URLs, API keys, feature flags, and secrets. Managing them across multiple environments (development, staging, production) is a common source of bugs, security issues, and deployment failures. This article is the founder's guide to keeping environment variables organized, secure, and consistent across environments.
The direct answer is that managing environment variables across environments requires four practices: separation (each environment has its own variables), documentation (a .env.example file lists all required variables), validation (the app validates variables at startup), and secrets management (secrets are never in code or committed files). For more on environment variables, see our article on a founder's guide to environment variables, secrets, and least privilege.
Practice 1: Environment Separation
Each environment (development, staging, production) has its own set of environment variables:
- Development. Variables are in a local .env file (gitignored). The database URL points to a local database. API keys are test keys (e.g., Stripe test key). Secrets are development-only (not production secrets).
- Staging. Variables are set in the Deployxa dashboard for the staging app. The database URL points to a staging database (a copy of production data). API keys are test keys or sandbox keys. Secrets are staging-specific.
- Production. Variables are set in the Deployxa dashboard for the production app. The database URL points to the production database. API keys are live keys (e.g., Stripe live key). Secrets are production secrets (strong, rotated regularly).
The key principle is: never share secrets across environments. The production database password should not be the same as the staging database password. If a staging secret is compromised, it should not give access to production data.
Practice 2: Documentation (.env.example)
A .env.example file (committed to the repository) documents all required environment variables:
# .env.example (commit this file)
# Database
DATABASE_URL=postgresql://user:pass@host:5432/dbname
# Authentication
JWT_SECRET=generate_with_openssl_rand_base64_32
NEXTAUTH_SECRET=generate_with_openssl_rand_base64_32
# Stripe
STRIPE_SECRET_KEY=sk_test_or_live_key
STRIPE_WEBHOOK_SECRET=whsec_xxx
# Email
RESEND_API_KEY=re_xxx
# App
NODE_ENV=production
PORT=3000
NEXT_PUBLIC_APP_URL=https://myapp.comThis file serves three purposes: (1) it documents what variables are needed, (2) it helps new team members set up their local environment, and (3) it helps the pre-flight scanner verify all variables are set before deployment.
Practice 3: Validation
Validate environment variables at startup, so the app fails fast if a variable is missing:
// lib/env.ts
import { z } from 'zod';
const envSchema = z.object({
DATABASE_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
STRIPE_WEBHOOK_SECRET: z.string().startsWith('whsec_'),
RESEND_API_KEY: z.string().startsWith('re_'),
NODE_ENV: z.enum(['development', 'staging', 'production']),
PORT: z.string().default('3000'),
NEXT_PUBLIC_APP_URL: z.string().url(),
});
const parsed = envSchema.safeParse(process.env);
if (!parsed.success) {
console.error('Missing or invalid environment variables:');
console.error(parsed.error.format());
process.exit(1);
}
export const env = parsed.data;This ensures the app does not start with missing or invalid variables, which prevents runtime errors (e.g., Cannot read property 'DATABASE_URL' of undefined).
Practice 4: Secrets Management
Secrets (API keys, passwords, tokens) need special handling:
- Never commit secrets to Git. Add .env to .gitignore. If a secret has been committed, remove it from history and rotate it.
- Never use `NEXT_PUBLIC_` for secrets. Variables prefixed with NEXT_PUBLIC_ (Next.js) are inlined into client-side JavaScript, which means anyone can see them.
- Rotate secrets regularly. Rotate production secrets every 90 days. For more on rotation, see our article on building an AI agent that manages your secrets.
- Use a secrets manager for large teams. For teams with many secrets, use a secrets manager (e.g., Doppler, AWS Secrets Manager) instead of plain environment variables.
For more on secrets management, see our article on the secrets management gap.
Common Pitfalls and Troubleshooting
The first pitfall is sharing secrets across environments. If the staging and production databases use the same password, a staging compromise gives access to production. The fix is to use different secrets for each environment.
The second pitfall is not validating variables. Without validation, a missing variable causes a runtime error (e.g., the app crashes when it tries to connect to the database). The fix is to validate at startup.
The third pitfall is build-time vs runtime variables. NEXT_PUBLIC_* variables are inlined at build time (they are baked into the JavaScript bundle). Changing them requires a rebuild. Server-side variables (without NEXT_PUBLIC_) are read at runtime and can be changed without a rebuild. The fix is to understand the difference and to use server-side variables for values that change between environments.
The fourth pitfall is not documenting variables. Without a .env.example file, new team members do not know which variables to set, which leads to missing variables and runtime errors. The fix is to maintain a .env.example file.
The fifth pitfall is not rotating secrets. Secrets that are not rotated are vulnerable to compromise. The fix is to rotate production secrets every 90 days.
Common Pitfalls and Troubleshooting
When working with how to manage saas environment variables across staging and production, several common pitfalls can undermine effectiveness. The first is over-automation. Automating everything sounds appealing, but some tasks require human judgment. The fix is to automate repetitive tasks (monitoring, diagnosis, deployment) while keeping humans in the loop for decisions that affect customers, billing, or security. The second is not testing changes before applying them. Whether it is a configuration change, a code change, or an infrastructure change, untested changes can break production. The fix is to always test in staging before applying to production, and to have a rollback plan. The third is not monitoring the automation itself. If your automated system goes down, you are flying blind. The fix is to monitor the automation system (e.g., with a dead man's switch) and to alert if it stops running. The fourth is not documenting the process. If the process is in your head, it does not exist for anyone else. The fix is to document the process in a runbook that anyone can follow. For more on documentation, see our article on how to build a deployment process your future team can inherit. The fifth is not reviewing regularly. Processes that work today might not work tomorrow (as the product grows, the traffic changes, the team changes). The fix is to review the process monthly and to adjust as needed.
Advanced Patterns and Best Practices
Beyond the basics of how to manage saas environment variables across staging and production, several advanced patterns can improve outcomes. The first is incremental implementation. Rather than implementing everything at once, start with the minimum viable version and iterate. This reduces risk (smaller changes are easier to debug) and delivers value faster. The second is automation. Manual processes are error-prone and do not scale. The fix is to automate repetitive tasks (deployment, testing, monitoring) using CI/CD pipelines and automated tools. For more on CI/CD, see our article on how we built the CI/CD pipeline. The third is documentation. A process that is not documented does not exist for anyone else. The fix is to document processes in runbooks that anyone can follow. For more on documentation, see our article on how to build a deployment process your future team can inherit. The fourth is testing. Untested changes can break production. The fix is to write tests (unit, integration, end-to-end) and to run them in CI/CD before every deployment. For more on testing, see our article on the testing void. The fifth is continuous improvement. Processes that work today might not work tomorrow. The fix is to review processes regularly (monthly) and to adjust based on lessons learned from incidents, feedback, and changing requirements.
When This Approach Is Not the Right Choice
While how to manage saas environment variables across staging and production is a valuable practice, it is not always the right approach. For very small projects (hobby projects, prototypes), the overhead of implementing best practices might not be worth the effort. The fix is to implement the minimum viable version and to add more as the project grows. For teams with limited resources (solo founders, small teams), prioritizing features over infrastructure might be the right call in the short term. The fix is to implement the highest-impact practices first (security, backups) and to defer the rest until the team grows. For projects with strict compliance requirements (HIPAA, SOC 2), the standard approach might not be sufficient, and you might need to implement additional controls (audit logging, access reviews, penetration testing). The key is to match the approach to your project's stage, resources, and requirements. For more on prioritization, see our article on the production checklist before your SaaS takes its first customer. For more on compliance, see the SaaS founder's guide to compliance.
Additional Considerations and Best Practices
When working with how to manage saas environment variables across staging and production, there are several additional considerations that can significantly impact your success. The first is the importance of starting simple and iterating. Many teams try to implement everything at once, which leads to complexity, bugs, and delayed launches. The fix is to start with the minimum viable version, verify it works, and then add features incrementally. This approach reduces risk, delivers value faster, and makes debugging easier because changes are smaller. The second consideration is the importance of documentation. A process that is not documented does not exist for anyone else on the team. Document your configuration, your deployment process, your rollback procedure, and your incident response plan. Use runbooks that anyone can follow, not just the person who set up the system. For more on documentation, see our article on how to build a deployment process your future team can inherit.
The third consideration is testing. Untested changes are the leading cause of production incidents. Before deploying any change, test it locally, test it in staging, and run your automated test suite. If you do not have automated tests, start by writing tests for your most critical paths (signup, login, payment). For more on testing, see our article on the testing void. The fourth consideration is monitoring. Without monitoring, you cannot detect issues until customers complain. Set up health checks, structured logging, metrics tracking, and alerts for error rate and response time. For more on monitoring, see our article on monitoring your SaaS without hiring a DevOps engineer.
The fifth consideration is security. Security is not optional when you are handling customer data and payment information. Ensure all secrets are in environment variables (never hardcoded), enforce HTTPS, set security headers, use rate limiting on auth endpoints, and hash passwords with bcrypt or argon2. For more on security, see our article on a practical security checklist for early-stage SaaS. The sixth consideration is backups and recovery. Your database should be backed up daily, backups should be stored off-site, and backup restore should be tested regularly. An untested backup is not a backup. For more on backups, see our article on how to rehearse a database restore before you need one.
The seventh consideration is cost management. Cloud costs can creep up over time, and without monitoring, they can exceed revenue. Track your monthly hosting cost, set a budget, and use fixed pricing (like Deployxa at $9/month for 15 apps) to avoid surprise bills. For more on cost management, see our article on how to estimate deployment costs for a small SaaS. The eighth consideration is team communication. When things go wrong, communication is as important as the fix. Set up a status page, communicate transparently during incidents, and publish post-mortems after. For more on communication, see our article on the SaaS founder's guide to status pages.
These considerations apply regardless of your specific technology stack, team size, or business model. By addressing each one systematically, you reduce the risk of outages, data loss, security breaches, and cost overruns, which protects your revenue and your customers' trust.
Conclusion: Organize, Document, Validate, Protect
Managing environment variables across staging and production does not have to be a headache. By separating environments, documenting variables (.env.example), validating at startup, and managing secrets properly, you can keep your configuration organized, secure, and consistent. This prevents deployment failures, security incidents, and team confusion.
Ready to organize your environment variables? Create a .env.example file, add validation, and ensure each environment has its own secrets. For more, see a founder's guide to environment variables, secrets, and least privilege and the vibe coder's guide to environment variables. Explore our free developer tools to speed up your workflow.