Why this matters
How to set up development, staging and production is mostly a design job, not a tool purchase. Each environment answers a different question. Development asks whether a change can be built and tested safely. Staging asks whether the release works under production-like settings. Production asks whether real customers get the right result. When those questions share one environment, every test is also a live change.
Separation gives you a blast radius and a clear permission model. Production credentials should never sit on a laptop, and a developer should not need write access to production data to fix a bug. Give each environment its own database, object storage bucket, queue, cache namespace, secret store path and DNS name. Shared resources create hidden coupling and make test traffic look like real traffic.
Parity matters more than size. Staging should use the same runtime version, database engine and major version, queue semantics, proxy behavior, TLS setup and authentication flow as production. It can run on smaller instances and fewer replicas. The bugs you want staging to catch usually come from configuration shape and dependency behavior, not from matching production capacity.
Before you start
Start with an inventory. List every app, service, background worker, scheduled job, database, bucket and third-party integration. Mark which ones already have separate credentials for test and live. Add the people and systems that deploy: laptops, CI runners, cron hosts, support tools.
Choose an isolation model before you create resources. Separate cloud accounts or projects give the strongest boundary, simplify billing reports and let you apply different guardrails per environment. Separate Kubernetes namespaces or a shared cluster are cheaper to run but share the control plane and need strict NetworkPolicy, resource quotas and role bindings. Write down why you chose the model, because changing it later is a migration.
Define the promotion path. A commit should produce one immutable artifact, such as a container image or build archive, and that same artifact should move from development to staging to production. Decide who approves each promotion and what evidence staging must show. Also decide how database migrations run in each environment and who can run them.
Prepare the supporting pieces: domain names and DNS zones, TLS certificates, identity provider applications for each environment, log and metric destinations, backup policy, and a secret manager. If your team is small, keep the first version simple. Three environments with clear rules beat six environments with no owner.
How to do it
Work from the outside in. Provision the environment boundaries first, then the deployment path, then the data and access rules. Use infrastructure as code for anything you will create more than once. Keep environment differences in variables and secret values, not in copied code branches.
Configuration should be injected at deploy time. Store non-secret settings in versioned config files or parameter stores with one key per environment. Store secrets in a secret manager and reference them by name. GitHub Environments, for example, can hold environment-scoped secrets and require reviewers before a production job runs. In AWS, use separate IAM roles per environment and let CI assume them through OpenID Connect instead of storing long-lived keys.
Non-production data must be safe and useful. Seed development with synthetic records or a small masked subset. Refresh staging from a sanitized snapshot on a schedule, and never restore a production dump into a lower environment without masking emails, phone numbers, addresses, tokens and payment references. For schema changes, run the same migration tool in every environment and test the rollback plan before production.
- Inventory environments and dependencies. List apps, services, databases, buckets, queues, cron jobs and third-party integrations. Note which ones already have separate test and live credentials. Assign an owner for each environment.
- Pick an isolation boundary. Use separate cloud accounts or projects for strong separation, or separate namespaces and clusters when cost matters more. Write down the trade-off and the access rules that follow. Do not mix production and non-production workloads on one shared host.
- Create the three environments. Provision development, staging and production with separate network ranges, databases, buckets and secret paths. Give each a clear DNS name and a tag that identifies the environment. Tag every resource so cost and access reports stay readable.
- Codify infrastructure and config. Write Terraform, CloudFormation or your platform's equivalent for the core resources. Keep one state file or workspace per environment. Put non-secret settings in versioned config and document every key.
- Set up secret stores and deploy roles. Create a secret manager path per environment and a deploy role per environment. Allow the development role to read only development secrets, and require an approval step for production. Rotate any key that was ever copied into a chat or a laptop.
- Build one artifact and promote it. Make CI build, test and scan a single artifact on every merge. Deploy that exact artifact to development, then staging, then production through a pipeline with gates. Never rebuild from a different branch for production.
- Seed and mask non-production data. Generate synthetic data for development and restore a masked subset for staging. Mask direct identifiers, credentials and free-text fields that may contain customer details. Test the masking job and keep its output out of backups that reach developers.
- Add guardrails and observability. Put branch protection, required reviews and environment protection rules in place. Send logs, metrics and alerts from each environment to a labeled destination. Add a dashboard that shows version, error rate and deploy status per environment.
- Rehearse promotion and rollback. Run a release through all three environments with a real migration and a feature flag change. Break staging on purpose and roll it back using the documented steps. Fix the gaps before you trust the process.
How to check it worked
Deploy the same commit through all three environments and compare what each one runs. The image digest or build checksum should match. Check that the environment name, database host and secret path differ at each stop, and that no production value appears in development logs.
Test access from the outside. A developer account should fail when it tries to write to production storage, and the production deploy role should fail in staging. Search repositories and CI logs for secrets that should only live in the secret manager. Confirm that a pull request cannot deploy to production without the required reviewer.
Test data handling and failure. Restore a masked snapshot into staging and verify that direct identifiers are gone. Run a failed deployment and a failed migration in staging, then follow your rollback notes. Check that alerts reach a person, not an unused inbox.
Ask a new engineer to deploy a small change using only the documentation. If they need a senior person to remember a password or a manual DNS step, the setup is not finished.
Mistakes to avoid
Do not let staging become a demo ground where anyone changes settings by hand. Drift destroys the value of the environment and hides problems until production. Make all changes through code or a documented change, and rebuild staging on a schedule.
Do not copy production data into development to debug a single record. Use a masked subset or synthetic records. If you must reproduce a bug, reproduce it in staging with sanitized data.
Do not keep long-lived branches named develop, staging and production and merge between them. That pattern creates different artifacts and merge conflicts. Promote one artifact through the pipeline and keep environment differences in config.
Do not stop at three environments with no owner. Assign one person to keep the environments, secrets and runbooks current. If you want outside help, Cloudverg's Delivery platform setup package at $14,500 fixed price is one option among others.
Frequently asked questions
Do I need a separate cloud account for each environment?
Not always. Separate accounts give the strongest isolation and simpler guardrails, but they add setup work. Separate projects, subscriptions or namespaces can work for smaller teams if access rules, quotas and network policy are strict.
Should staging use production data?
No. Use a masked subset or synthetic records that preserve the shape of production without exposing customer data. Test the masking process and keep raw production backups out of lower environments.
How many environments should a small team start with?
Start with development, staging and production. Add short-lived preview environments for pull requests only when they solve a real review problem. Each environment needs an owner, a cost limit and a cleanup rule.