The environment — a named target that remembers
The release has passed its checks and is waiting outside production. Ada is the named reviewer tonight. She reads the change, the artifact and the rollback plan before approving it. A GitHub environment can provide that pause when the repository’s plan and visibility support the required protection rules. A name such as “production” in YAML alone does not create an approval gate.
Naming the target is not bureaucracy; it is the move that turns "we deployed something" into "we can trace and govern what deploys here." Two microservices with their own pipelines can both target the same production environment, and the environment's history stitches their separate runs into one legible sequence of who changed production and when. That single fact — one accountable record of every landing — is worth naming for on its own; the gates you hang on it are the second dividend.
- Environment
- A named deployment target that records deployment activity and can apply protection rules to jobs that target it.
Create the environment in repository Settings → Environments and configure its protection rules there. Use a short set of names that match real targets, such as staging and production. Restrict production to the intended branches and add an eligible reviewer when the repository plan supports it. Keep the rule outside the workflow file so a pull request cannot quietly remove the protection it depends on.
Classes Twenty-Two through Twenty-Four introduced the GitHub Actions building blocks. This part applies them to deployment control: the job names an environment, repository settings define its protection rules, and the job starts only after those rules pass. Azure OIDC determines how the job signs in; an environment approval determines when it may start. Those are separate controls.
A pipeline you can't diff is folklore.
The approval — the human gate before production
An approval is the simplest and most important gate: before a stage is allowed to deploy to the environment, the run pauses and waits for a named human — or any one of a named group — to say yes. Nobody's merge silently reaches customers at four on a Friday; a person looked at what was about to ship and put their name to it. This is the same idea you already met as GitHub Actions environment protection rules back in Class Twenty-Three — the noun is different, the control is identical — which is exactly why the discipline travels: learn "a human gate lives on the environment" once and you can find it in either platform on the first morning.
The load-bearing detail — the one this whole part turns on — is where the approval is configured. It is not in the YAML. The pipeline author writes only environment: production; the approval is attached to the production environment itself, in the web interface, by the environment's owner. That separation is deliberate and it is a security boundary: a developer editing the pipeline file cannot grant themselves a shortcut past production, because the gate does not live in the file they can edit. It lives on the resource, and only a resource administrator can change it.
# .github/workflows/deploy.yml — environment on the job jobs: deploy: needs: build runs-on: ubuntu-latest environment: production steps: - uses: actions/checkout@v6\n - run: ./release.sh # This file names the environment. Configure required reviewers, # branch restrictions, and other supported rules in repository # Settings > Environments. The name alone does not add a gate.
When you add the approval you choose the approvers — users or groups — set a timeout after which the stage is marked skipped rather than left hanging forever, and decide one small setting that turns out to matter enormously: whether an approver is permitted to approve their own run. Leave that permitted and the gate becomes theatre; restrict it and you have separation of duties, the difference explored in §4. If a group is named, only one member need approve — a deliberate convenience, so a single person's holiday does not stop every release, but also the first thing an attacker studies when they want a rubber stamp.
The checks — the machines that gate beside the human
An approval is a person; a check is a machine. Both are gates on the environment, both pause the stage until satisfied, and both are configured in the same place — the environment's Approvals and checks tab, never in the YAML. The difference is who decides: an approval waits for human judgement, a check evaluates an automated condition and passes or fails on its own. Keep the two words apart, because "we have approvals" and "we have checks" answer different questions — who agreed versus what was verified — and a mature production door usually has both.
Approvals gate who; checks gate what.
GitHub environment protection rules can include required reviewers, wait timers, and deployment branch or tag restrictions; organisations may also configure custom protection rules where supported. These controls are configured in repository settings, not declared as steps in workflow YAML. A required reviewer can approve or reject a pending deployment. Check current GitHub plan limits, especially for private repositories, before you design a release around a rule.
| Control | What it does | Important limit |
|---|---|---|
| Required reviewers | Pauses a deployment job for review before it starts | Availability depends on repository plan and visibility; configure outside workflow YAML |
| Deployment branches and tags | Limits which refs may deploy to the environment | Must be configured in the environment settings |
| Wait timer | Delays a deployment for a configured period | It does not observe application health |
| Custom deployment protection rule | Allows an external service to approve or reject a deployment | Requires an integration and supported plan |
| Concurrency control | Prevents conflicting jobs from changing the same target at once | Configure at the workflow or job level; it is not an approval |
The pattern under the menu is simple: a check lets the resource owner, not the pipeline author, impose a condition that every pipeline consuming that environment must satisfy. wait timers turns "please don't deploy overnight" from a Slack plea into an enforced rule; external monitoring checks turns "watch the dashboards after the canary" into a gate the machine holds; required workflow policy quietly makes a security baseline non-optional. You will not use all of them, and you should resist bolting on checks you cannot explain. But knowing the menu means that when a governance requirement lands on your desk, you reach for the check that already exists instead of writing a fragile script to reinvent it.
The discipline — gates decided while it is calm
The machinery of this part is a morning's work; the judgement is the career. Three habits separate an engineer whose gates protect production from one whose gates are decorations. The first: decide the gates while nothing is on fire. An approval invented at deploy time — added in a panic because a bad release just went out — is a reaction, not a policy, and it will be quietly bypassed the first time it is inconvenient. Sit down when the estate is calm and write down what production requires: who approves, what checks must pass, from which branches. A gate you designed in daylight survives the 3am pressure to skip it; one you bolted on mid-incident does not.
The second: least privilege on who can approve. The approver list is a permission, and it should be as short as the risk demands and no shorter — the people who can actually judge whether this release is safe, not the whole team for convenience. And the setting that quietly decides whether the gate is real: restrict approvers from approving their own runs. An engineer who can deploy and approve their own deploy is a gate with no one on the other side of it — separation of duties collapses into a formality. Permit self-approval only where the risk genuinely does not warrant a second person, and know that you have done so.
A rubber stamp is not a gate.
The third follows from the second: the approver who rubber-stamps is worse than no gate at all, because they manufacture the appearance of control while providing none. A gate everyone knows is real slows people into looking; a gate that always says yes within four seconds trains the team that production sign-off is a formality, and the audit trail lies on your behalf. If an approval is not being read, you do not have an approval — you have a delay with a signature on it. The fix is not more gates; it is fewer approvers who actually look, and automated checks doing the mechanical verification so the human is spending their judgement on the thing only a human can judge.
A gated staging-to-production flow under the warehouse deploy
Basecamp's warehouse deploy — the one an engineer used to do by hand on Friday nights — now has a real pipeline from the earlier parts, and this part gives it a door. The reader creates two environments. Staging deploys automatically on every merge to main: no approval, so the team gets fast feedback and a running copy to test against, and its deployment history quietly records every landing. Production is a separate environment with a manual approval naming two owners — the warehouse lead and one Campux engineer — with self-approval restricted, so the person who wrote the change cannot be the one who waves it through. No warehouse release reaches customers until one of those two humans has looked and confirmed.
The decision that matters is not the tooling — it is that Campux wrote the gate down while the estate was calm, in the first quiet week of the acquisition, rather than after a bad release forced it. The staging environment absorbs the mistakes; the production approval catches the one that staging missed. The Basecamp engineers, braced to have their Friday ritual mocked, instead watch it become the safest deploy they have ever run — automatic where speed is cheap, gated exactly where a customer would feel the error.
Play it through
Three minutes. Staging deploys on every merge, and that is right. Watch production with no door of its own, then sort a human approval and an automated check onto the one environment that needs them. It plays on its own and stops when it needs your hands.
Why the gate is the part a hiring manager can read
Of everything in a pipeline, the production gate is the line that reveals how you think when no one is watching. A hiring manager asking "how does a change reach production on your team" is really asking whether a merge silently deploys at 4pm on a Friday or whether a named human looked first; whether the person who wrote the change is the same person who approved it; whether "don't deploy during peak" is a Slack message or an enforced check. Those answers are not preferences — they are the difference between an engineer a team trusts with production and one it does not. Every one of them is a decision you hang on an environment, in daylight, and can defend out loud.
So carry the shape, not the menu. The environment is the door and the record of who came through it; the approval is a human before customers feel the change; the checks are the machines verifying what a human should not have to. Name the target, hang the right gate on it, keep the approver list short and the self-approval switch honest — and you can answer the interview question in three sentences and back it on the job the same afternoon. That is the whole of this part: not the clicks, but the judgement of where a door belongs and who holds its key.
The release nobody had to be brave to ship
A teammate merges the warehouse fix. It deploys to staging on its own, and the deployment history logs it. Production waits: the run pauses on the approval, one of the two named owners reads the diff, confirms, and the release goes out — traceable, reviewed, and impossible to have shipped by accident. No one clicked into a server, no one held their breath, and if a Monitor alert had fired the check would have held the door on its own. You did nothing heroic. You decided, while it was calm, where the door was and who held the key — and the calm is exactly the achievement.
Carry the same build forward
Before setup, check what your account can do. Required reviewers on environments work on public repositories on every plan; on a private repository they need a paid GitHub plan. Solo path: use a public practice repository and add yourself as the reviewer (leave "prevent self-review" off), so you can see the pause and approve it. Observe-only path: if neither works for you, read the continuation's supplied run log and mark the pause, the approver and the timestamp; say "observed", not "configured". Use the same disposable repository and artifact from the first workflow lab. Its supplied continuation gives you a failing content check, a skipped downstream job, checksum verification and an optional observable approval pause. Read the account prerequisites before claiming that a gate exists.
Examination
Four drills, then two situations. Write your answer before you reveal the reasoning, or the exercise is worthless. Nothing is stored.
B — the gate does not live in the file the developer can edit. The pipeline author writes only the environment name; the approval is configured on the production environment itself, in repository Settings → Environments → Approvals and checks, by a resource administrator. That separation is the point: if approvals lived in the YAML, anyone who could edit the pipeline could grant themselves a shortcut past production, and the gate would protect nothing. A is the intuitive-but-wrong answer that the whole design exists to defeat. C describes real damage — dropping the environment name does forfeit history and protection — but it does not remove the approval, it removes the target the approval guards, and an administrator would notice a job that no longer deploys anywhere accountable. D confuses environment checks with branch policies. The durable fact: the file names the door; the lock is hung on the door.
B — an approval is a person, a check is a machine. The external monitoring checks gate is an automated check: it passes on its own when no alert rules are active, no human involved. The sign-off is an approval: it waits for a named human's judgement. Both are configured on the environment, both pause the stage, but they answer different questions — what was verified versus who agreed — and conflating them is how teams end up thinking a green automated check means someone looked, or that a human approval proves the system is healthy. A and C collapse the distinction the whole section is built on. D is the recurring error of this part: these are resource-owner controls on the environment, deliberately kept out of the YAML so a pipeline author cannot weaken them. Keep the pair straight: checks gate what; approvals gate who.
Environments record history; self-approval must be restricted for separation of duties; wait timers and Monitor are owner-set checks. Those three are the load-bearing facts. The two rejects are the confusions to burn out. Approvals and checks are emphatically not in the YAML — they are configured on the resource by its owner, so a pipeline author cannot edit past them; believing otherwise is exactly the mistake that lets someone assume the gate is in reach of anyone who can touch the file. And when a group is the approver, only one member need approve — a deliberate convenience so a single holiday does not freeze every release, but also the reason a large approver group can quietly become a rubber stamp, since it only takes the one person who never reads. Size approver groups the way you size any permission: as small as the risk allows.
# production gate — warehouse deploy
1. Target a named 'production' environment so every
release is recorded in deployment history.
2. Add a manual approval on the environment naming
the warehouse lead and one Campux engineer.
3. Leave "approvers may approve their own runs" ON,
so whoever deploys can just approve it themselves
and we don't get blocked waiting.
4. Add a wait timers check so nothing deploys
to the warehouse system overnight.
Line three — the gate now has no one on the other side of it. An approval exists so that someone other than the author looks before a change reaches customers. Leaving self-approval permitted means the person who wrote and deployed the warehouse change is the same person who waves it through — separation of duties collapses into a click, and the audit trail records a sign-off that verified nothing. The whole apparatus of environment, history, and named approvers is intact, and this one setting quietly makes it decorative. The fix is one toggle: restrict approvers from approving their own runs. The distractors are the plan at its best — history is the reason to name the environment (A inverts it), two named approvers with self-approval restricted is exactly right so a holiday does not freeze releases (B), and wait timers is a genuine check that holds overnight deploys (D). The test for any gate: who is actually on the other side of it? Here, until line three is fixed, no one is.
The trap is that the shortcut is one click and technically within your power. You have admin; you could add yourself and approve your own change in ten seconds. But that is the exact move the gate exists to prevent — the deployer approving their own deploy is separation of duties collapsing into a formality, and doing it once, under pressure, is how it becomes the normal path. The approval is not being annoying by accident; it is being annoying on purpose, and the moment you bypass it because a customer is waiting is the moment it stops protecting the next customer.
Separate the urgent from the permanent. If this release genuinely cannot wait, the right escape hatch is not self-approval — it is finding a legitimate second human. Is there another authorised approver, or an on-call lead who can be added and asked to actually look? A real review by someone other than the author, even hurried, preserves the control; a self-approval destroys it. If no qualified second person can be reached, then the honest answer is that the release waits, and you say so — "we designed production to need a second set of eyes, and I'm not going to be the one who quietly removes that on a Friday."
Fix the system, not just tonight. The real defect is that a two-person approver list with no coverage can strand a release at 4:30 on a Friday. That is a rota problem: widen the approver group enough that someone qualified is always reachable, or define a documented break-glass procedure that is logged and reviewed — not an ad-hoc "the admin approved their own thing." Raise it Monday. The seniority here is refusing a defensible-sounding shortcut and turning the incident into the reason the gate finally gets staffed properly.
Answer as a structure, not a list of tools. "Every deploy lands on a named environment, and the environment is where I hang the controls." Then walk it: staging deploys automatically so the team gets fast feedback, and its deployment history records every landing — which commit, which run, when — so I can always say what is actually running. Production is a separate environment, and it is the door I lock.
Name the two kinds of gate and where they live. "On production I put a manual approval — a named human, not the person who wrote the change, confirms before it ships, so nothing reaches customers by accident at 4pm on a Friday. Beside it I put automated checks: a Monitor-alerts check so a deploy holds if the system is already unhealthy, wait timers so nothing lands overnight. And the load-bearing detail — none of that is in the YAML. The pipeline author just writes the environment name; the approval and checks are configured on the environment by its owner, so a developer editing the file cannot approve past their own change." That one sentence tells the interviewer you understand it as a security boundary, not a convenience.
Close on the judgement, not the clicks. "The reason I answer it as a door rather than a feature is that it's the same idea on GitHub Actions — a human before customers feel the change, machines verifying what a human shouldn't have to, and the gate decided while it's calm rather than bolted on after an outage. What's portable isn't the tool; it's knowing where a door belongs and who holds its key." That reframes you from "person who can click approve" to "engineer a team trusts with production" — which is the whole point of the part.
Five things worth carrying out of this part
- An environment is a named deployment target a deploy job points at with environment:. Naming it buys deployment history — a legible record of what landed and when — and a place to hang protection.
- An approval is the human gate: the run pauses until a named person (or one of a group) signs off — the same idea as GitHub Actions environment protection rules from Class Twenty-Three.
- Approvals and checks are configured on the environment by its owner, never in the YAML. The pipeline author only names the door; the lock is hung on the door — a deliberate security boundary.
- A check is a machine, an approval is a human. Checks gate what (Monitor alerts, wait timers, required workflow policy, concurrency controls); approvals gate who. A production door usually has both.
- Decide the gates while it is calm, keep the approver list short, and restrict self-approval — an approver who is also the deployer, or one who rubber-stamps, is worse than no gate at all.
- A GitHub Actions environment is a named deployment target that records deployment history and can carry protection rules. Jobs declare the environment in YAML; administrators configure supported reviewers, branch restrictions, and other available rules in repository settings. ↩
- GitHub environment protection capabilities depend on the repository plan and visibility and can change. Verify current availability in GitHub repository settings and official documentation before making a release design depend on a specific protection rule. ↩
Gate a deployment with an environment, an approval and a check.
Play the lesson above to stamp this class.