code-freeze
How to Handle Emergency Deploys During a Code Freeze
An emergency deploy during a freeze needs a structured approval path, not a workaround. Here is how to design one that is fast enough to use and controlled enough to trust.
An emergency deploy during a code freeze should go through a structured override workflow, not around the freeze entirely. If your current plan is "find someone with admin access to disable branch protection," you have a gap: the barrier is too informal, too slow when it matters, and leaves no audit record. A real override path is defined before the freeze starts, requires a second approver, and keeps the rest of the freeze intact while one change clears.
What counts as an emergency during a freeze?
An emergency during a freeze is a change that, if held until the freeze lifts, causes measurable harm that the freeze itself is not designed to protect against.
The clearest cases:
- A customer-facing outage or significant degradation (site down, checkout broken, data not loading)
- A security vulnerability being actively exploited or with a public disclosure window
- Data corruption that will worsen the longer the bad code runs
- A revenue-blocking bug confirmed in production, not just in staging
The ambiguous cases that usually are not emergencies:
- A bug that is annoying but has a workaround
- A feature that was promised to a customer but is not yet broken
- A change someone wanted to ship before the quarter ended
- A deploy that has been ready for a week but no one prioritized it before the freeze
The freeze creates pressure to reclassify the second category as the first. That pressure is exactly what the override approval step is there to resist. When in doubt, the test is: "Would we wake someone up for this at 3am on a normal week?" If not, it is not a freeze emergency.
Why do you need an override path at all?
Production breaks. That is guaranteed. A freeze covers a window of risk, not a window of perfection, and some fraction of the problems that surface during a freeze will require a fix faster than the freeze end date.
If there is no defined override path, engineers will find a way through. They will ask an admin to manually disable a branch protection rule, merge directly to a release branch, or push to staging and copy the change to production by hand. Those workarounds are faster to start but slower to finish: they skip review, skip notification, and leave no record of what happened or who approved it. The next time someone looks at the audit log for that incident, the critical hotfix is invisible.
A structured override path is faster in practice than the workaround, because everyone knows the steps ahead of time and the tooling supports them. It is also the only way to maintain the audit trail that compliance reviews and post-incident analyses depend on.
What does a good override workflow look like?
The key design constraint is that an override should require two people but not require an admin to take any manual action on the freeze configuration itself. Specifically, the override clears one change through while the freeze stays active for everything else.
A workflow that holds up under pressure:
- The engineer who needs the fix opens an override request, briefly describing the change and the customer impact (one paragraph is enough).
- A second approver, typically an on-call lead, release manager, or engineering manager, reviews the request and either approves or denies it. The approver should be reachable on-call, not just someone who happens to be online.
- If approved, the merge or deployment proceeds automatically. The approver does not manually reconfigure anything.
- The action, the approver, and the timestamp are logged immediately. The freeze stays active.
The second approver requirement is not bureaucracy for its own sake. It keeps individual engineers from self-approving urgent-but-not-emergency deploys under pressure. It also gives the on-call lead awareness of what is going out during the freeze, which matters when diagnosing a problem that emerges later.
How should you scope an override?
The override should clear a specific change, not the whole freeze.
If your override process is "pause the freeze for 30 minutes," you have eliminated the freeze for that window. Every other change that can be merged or deployed during those 30 minutes will be, not because anyone decided it was safe but because the window opened. The point of a granular override is that it is surgical: one PR, one deployment, approved explicitly, everything else unchanged.
This is also why per-repo and per-environment scoping matters. If your freeze covers your billing service and your checkout service, an emergency in billing should not require touching the rules for checkout. The override should target the exact repo and environment where the change needs to land.
How should you set up the override path before the freeze?
The override path needs to be defined and communicated before the freeze starts. Setting it up at 11pm during an incident is too late.
Before any planned freeze, document and share:
- Who can approve an override (specific people or an on-call role, not "any senior engineer")
- How to reach them (a dedicated on-call channel or paging rotation, not just their personal Slack handle)
- What information the requester should provide (one sentence on customer impact is enough)
- What happens after approval (the specific steps, so the engineer with the fix knows what to do next)
- Where the approval and the resulting change are recorded
The last point often gets skipped. After the incident is resolved, someone will want to know what changed during the freeze and who authorized it. If that record lives only in a Slack thread, it is fragile and incomplete. The audit trail should be automatic, not reconstructed after the fact.
What are the common failure modes?
| Failure mode | What it looks like | What happens |
|---|---|---|
| No override path | Freeze exists, but no documented exception process | Engineers find the admin and ask to "just disable it for a minute" |
| Override requires admin action | Admin has to manually modify branch protection rules | Override takes 30-90 min; freeze disabled globally during that window |
| Anyone can self-approve | Single-person override with no second approver | Low-urgency changes get pushed through under "emergency" framing |
| No audit trail | Override happens but is not logged | Post-incident review cannot reconstruct what changed during the freeze |
| Override path not communicated | Workflow exists but no one knows how to use it | Engineers fall back to workarounds anyway because the path was not findable |
The most common failure is the second one. When the override requires an admin to manually reconfigure GitHub branch protection, the friction is high enough that the first instinct is to find a workaround instead. And the workaround leaves the freeze globally disabled for longer than intended while the admin finishes, sometimes across an entire repo or branch pattern, not just the one change that needed to land.
How does this look at the GitHub level?
GitHub's required status checks are the enforcement layer for merge freezes. A freeze tool (including NoShip) registers itself as a required status check. When the freeze is active, the check fails for all PRs. When an override is approved for a specific PR, the check can pass for that PR without the freeze being lifted globally.
That is the key difference between a purpose-built freeze tool and a branch protection rule you toggle manually. The branch protection rule is global: disabling it opens the branch to everyone. A freeze tool's override can be scoped to one PR, one repo, or one environment while leaving every other check in place.
GitHub's deployment protection rules follow similar logic for deployments: required reviewers and wait timers are environment-scoped, so you can gate production deployments without affecting staging.
See how to freeze deployments in GitHub for the full mechanics of setting up deployment protection rules alongside merge freezes.
How should you document overrides after the fact?
Every override during a freeze should leave a record that answers three questions:
- What changed? (The commit or deployment, not just "a hotfix")
- Who approved it? (A named person, not a role)
- Why was it classified as an emergency? (The original customer impact description from the request)
That record belongs in an audit log tied to the freeze, not in an incident ticket or a Slack thread. After the freeze lifts, it should be readable without reconstructing the context from three different systems.
This matters for two reasons: compliance (SOC 2 and ISO 27001 change management controls look for demonstrable approval workflows and audit trails) and post-incident reviews (when the next incident happens, the first question is "what changed?", and "changed during a freeze" narrows the candidate set considerably).
How NoShip handles emergency overrides
NoShip's override workflow is built on the dual-approval model described above. When an engineer needs an emergency merge or deployment during an active freeze, they request an override through NoShip or through the Slack integration. A second approver, whoever is designated for the current freeze window, reviews and approves. The specific PR or deployment clears; the rest of the freeze stays active. Every override, who requested it, who approved it, and when, is recorded in the audit log automatically.
The override is PR-scoped, not freeze-scoped. Approving one emergency deploy does not open the freeze to everything else. That scoping is what makes the workflow practical: the approver is authorizing one specific change, not making a judgment call about the entire freeze state.
If your current emergency deploy process is "find the person who set up the branch protection rule and ask them to pause it," the dual-approval pattern is a direct replacement. The concepts guide covers how freeze rules and override workflows are configured.
A freeze with no override path is not a safer freeze, it is just one that engineers will route around when something real breaks. Build the override path first, document it, and make sure everyone on the on-call rotation knows how to use it before the freeze starts.
Keep reading
How to Manage the Deploy Backlog After a Freeze
The deploy backlog after a code freeze is the most dangerous part of the freeze. Here is how to release the queue in a controlled order instead of all at once.
How to Set Up Recurring Code Freeze Windows
A recurring code freeze runs on a schedule automatically. Here is how to configure Friday windows, quarterly freezes, and biweekly release patterns in RRULE.
Code Freeze Best Practices: A Checklist for Release Managers
Code freeze best practices: scope, duration, automated enforcement, a real override path, and thaw planning. A practical checklist for release managers.