Create a production environment in GitHub, add required reviewers, restrict deployment to protected branches, and store the deploy credentials as environment secrets. A job that references the environment then pauses until a reviewer approves, and it cannot read those secrets before that. Check your plan first, because private repositories have limits.
What an environment gives you
GitHub's deployment documentation lists the protection rules you can attach to an environment:
- Required reviewers: up to six people or teams, and one approval is enough.
- Wait timer: a delay from 1 minute up to 30 days.
- Deployment branches and tags: no restriction, protected branches only, or selected name patterns.
- Admin bypass: administrators can bypass protections by default, and you can turn that off.
Environment secrets are only available to jobs that reference the environment, and if reviewers are required, not until one approves. That makes the approval a real gate in front of the credentials, not only a button.
Set it up in five steps
- In repository settings, create an environment named production.
- Add required reviewers, ideally two people so one can be away.
- Enable the option that prevents self review. GitHub's docs say that with it on, whoever starts a deployment cannot approve it, so a second person always reviews.
- Restrict deployment branches to your main branch or a release pattern. Remember that wildcards do not match a slash.
- Move the cloud keys or tokens into the environment's secrets, and delete any repository level copy.
Then reference the environment in the deploy job:
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- run: ./deploy.sh
Plan limits to check
The docs state that on GitHub Free, Pro and Team plans, required reviewers, wait timers and admin bypass control are available only for public repositories, and that environment secrets in private repositories need Pro, Team or Enterprise. Plan tables change, so confirm against the current docs before you rely on this for a private repository. If approvals are not available to you, a second job that waits on a protected branch merge plus a CODEOWNERS review is a workable fallback.
Pitfalls
- Self-hosted runners. The docs note that workflows on self-hosted runners are not isolated in a container even when they use environments. Treat environment secrets like repository secrets there.
- Branch rule that is too wide. If you add a rule for pull request merge refs, workflows triggered by pull requests can deploy to the environment.
- Admin bypass left on. If one admin can force a deployment, your approval is advisory.
- Approvals as a habit. If reviewers click through, you have a delay, not a control. Show the diff and the commit in the approval request.
Pair it with a pre-merge check
Approval at deploy time is late. Catch dependency and policy problems earlier, at the pull request. Safeguard's gates can block a merge on policy, so the approver sees changes that already passed.
Click through it at your own pace, or open it full screen.
Quick check
Can the person who triggers a deploy approve it?
Only if you allow it. Turn on the prevent self review option so that a second person always approves.
Do approvals protect environment secrets?
Yes. Jobs cannot read environment secrets until a required reviewer approves, provided the job references the environment.
Sources
Last reviewed: 19 October 2026.