Why promotion needs structure
In an unstructured release process, “promotion” means a developer re-running a deploy with a different parameter. Staging gets whatever is on a branch. Production gets a rebuild from a tag. A release is approved by someone replying “looks good” in a chat thread. When something breaks, nobody can say which build is running, who approved it, or whether it ever passed the tests that supposedly guard it.
Environment promotion gates replace this with a defined path. They are one of the central ideas in a well-built CI/CD pipeline: code moves forward only when specific evidence exists, and each step is recorded.
What good promotion looks like
- One artefact, many environments. The container image or package is built once, identified by commit SHA or digest, and deployed unchanged to each stage.
- Configuration is separate from the artefact. Environment differences (URLs, replicas, credentials) come from configuration, not from different builds.
- Gates match risk. Development deploys automatically. Production requires evidence and, where appropriate, a person.
- Enforced, not advised. The platform blocks the deploy if conditions are unmet.
- Auditable. You can answer “what changed, who approved, when” without detective work.
How it works in practice
The environments
A typical, deliberately small layout:
| Environment | Purpose | Deploy trigger | Gate |
|---|---|---|---|
| Dev or preview | Fast integration feedback | Every merge to main, or per pull request | Build and unit tests pass |
| Staging | Production-like verification | Automatic after dev succeeds | Smoke and integration tests, scan results |
| Production | Real users | After staging passes | Approval, change window if required, health checks |
We resist adding environments unless they have a distinct job. Each one costs money, needs maintaining and drifts from the others over time.
Automated gates
Automated gates are cheap and should do most of the work. Examples that we typically configure:
- Smoke tests against the freshly deployed environment, covering login, a critical API path and a database round trip.
- Health checks and readiness probes that must succeed before traffic shifts.
- Security gates that fail promotion on critical vulnerabilities, covered in our image scanning work.
- Policy checks, for instance that the image comes from your registry and runs as a non-root user, using a policy engine such as Open Policy Agent.
- Branch rules: only commits from the protected main branch may reach staging or production.
Human approvals
Human approval should be rare, informed and enforced by the platform. In GitHub Actions, the mechanism is the environment key plus protection rules configured in repository settings:
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging
steps:
- run: ./deploy.sh staging ${{ needs.build.outputs.digest }}
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment:
name: production
url: https://app.example.com
steps:
- run: ./deploy.sh production ${{ needs.build.outputs.digest }}
The approval itself is not in the YAML. Required reviewers, wait timers and branch restrictions are set on the production environment, so a developer cannot remove the gate by editing a workflow file. Environment secrets are only released to a job after protection rules pass. GitHub Actions environments, GitLab protected environments, Azure DevOps approvals and checks, and Jenkins input steps all provide the same idea, though features vary by plan, so we confirm what your tier supports before designing.
For Azure shops, our Azure DevOps pipelines guide covers environments and checks in more depth.
Scoping credentials per environment
Gates are weakened if every environment shares credentials. Staging should have no way to touch production data. We create separate cloud roles per environment, assumed through short-lived federation, and restrict which branches and workflows may assume the production role. See secrets management integration for the mechanics.
Decisions and trade-offs
Approval versus automation. A manual approval is a safety net and a bottleneck. For a team with weak automated tests, approval is the pragmatic control. For a team with strong tests, canary releases and quick rollback, approvals add delay without much safety. We often start with approval, then retire it as evidence accumulates. Pairing gates with automated rollback is what makes removing them safe.
Who approves. An approver who cannot judge the change is theatre. Approval works when the approver sees what is changing, test results and the diff since the last release. For small teams, two-person review on the pull request often provides the real control, and a production approval just confirms timing.
Change windows. Regulated or customer-facing systems sometimes need deployments only during agreed hours. A scheduled or timer-based gate handles this without blocking staging.
GitOps alternative. If you deploy to Kubernetes with a GitOps controller, promotion can be a pull request that bumps a version in an environment directory. The approval is the merge. This is covered in Kubernetes deployment via Helm or Argo CD.
When not to add gates. A solo developer deploying a low-risk internal tool does not need a three-stage approval process. Gates cost speed, so they should buy real risk reduction.
Common failure modes
- Rebuilding per environment, so staging results do not describe production.
- Approvals as rubber stamps because approvers lack context.
- Shared secrets across environments, which lets a staging bug reach production.
- Gates that can be edited away because they live in the same workflow file the developer controls.
- Environment drift, where staging is missing a service or setting that production has.
- Everyone is an approver, including the author of the change.
Delivery and handover
We map your current release path, agree the environment model and gates with you, and configure them in your platform. Workflow changes are reviewed in your repositories. You receive a short document describing each gate, who approves what and how to change a rule, plus a dry run of a production release with your team watching.
How to tell it is working
Watch lead time from merge to production, the proportion of releases that needed manual intervention, change failure rate, time spent waiting for approval, and whether every production deploy has a linked approval and artefact digest. Gates that never block anything may be too light; gates that block everything may be too heavy. If you want a quick view of where your process stands, try the DevOps maturity assessment, or book a consultation.