What are required status checks?
Required status checks are named check results that must pass on the last commit before a pull request can merge into a protected branch. On GitHub, a branch protection rule or a ruleset lists them by name. A failed or missing result stops the merge until a later run passes.
A status check is a result that an outside system, e.g. a continuous integration and delivery (CI/CD) pipeline, reports on one commit. A protected branch is a branch with rules on how changes reach it. GitHub's documentation calls these branch protection rules, and required status checks are one of their settings.
A ruleset is a named list of rules for branches or tags, described in GitHub's ruleset documentation. Several rulesets and a branch protection rule can apply to one branch, and the most restrictive version of each rule applies.
Required checks are a common way to put a quality gate in front of the main branch.
How do required status checks work?
A required status check works in six steps:
- An admin adds a rule for a branch, e.g.
main, in the repository's Branches or Rules settings, and lists by name the checks that must pass. - A developer or a coding agent pushes a commit to a pull request that targets that branch.
- CI runs on that commit and reports each result under a name. In GitHub Actions, each job reports a check named after the job, and the job fails when a step returns a nonzero exit code.
- GitHub matches the results on the pull request's last commit to the required names.
- GitHub counts a required check as passed when its result is successful, skipped, or neutral.
- GitHub allows the merge only when each required check has passed. A failed check blocks the merge, and a check that has not reported shows "Waiting for status to be reported."
GitHub calls required checks strict when the rule's "Require branches to be up to date before merging" option is on. The strict setting blocks the merge until the branch has every commit on main. A rule can also name the app that must report each check, and then a status from anyone else blocks the merge. The rule matches names, so a renamed job leaves it waiting for the old name. A branch protection rule's search lists only checks that passed in the past 7 days, so a job must pass once first.
What is an example of a required status check?
Here is an illustrative example. Acme Co. sells furniture online. The workflow for its web store runs two jobs on each pull request:
name: ci
on: pull_request
jobs:
unit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- run: npm ci && npm test
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- run: npm ci && npx playwright install --with-deps
- run: npx playwright test
An admin at Acme adds a branch protection rule for main that requires both jobs, names the GitHub Actions app as their source, and turns on the strict setting. GitHub's REST API returns the rule's status check settings like this, with URL fields left out:
{
"strict": true,
"contexts": ["unit", "e2e"],
"checks": [
{ "context": "unit", "app_id": 15368 },
{ "context": "e2e", "app_id": 15368 }
]
}
A developer asks a coding agent to "Let customers edit their delivery address during checkout." The change then meets the rule:
- The agent opens a pull request, and both jobs run on its commit.
- The
unitcheck passes, ande2efails on the cart test. The address saved, but the cart emptied. - GitHub lists
e2eas a failed required check and blocks the merge. - The agent fixes the code that cleared the cart and pushes again.
- Both checks pass, but another pull request has merged into
main. The strict setting makes the agent update the branch frommain, and the checks run again.
This example is simplified. A real project would also require an approving review.
What changes when a coding agent writes the code?
GitHub's documentation says any person or integration with write permissions can set any status check, and an agent often has that access. If Acme later adds a path filter that skips the ci workflow, no e2e check reports. An agent told to merge the change can then post a success status named e2e through the API. A rule that names no app counts it, but Acme's rule names the GitHub Actions app and blocks the merge.
Naming the app does not stop job edits. For a pull_request event, GitHub Actions runs the workflow file from the pull request's trial merge commit. If an agent adds if: false to the e2e job, the skipped job reports success from the right app. The checkout test never runs.
A practical adjustment is to pin each required check to its app and require a code owner's review for .github/workflows. Give the agent a token without admin rights or permission to update workflow files, so its pushes cannot change the jobs. A CI step can restore the test files from the base branch before the tests run, e.g. git checkout FETCH_HEAD -- tests/ after git fetch origin main. An agent editing tests in its branch then cannot turn the run green. Avoid pull_request_target for this, because it runs with the repository's secrets.
Which checks should be required?
A required check stops each merge it fails, so it should fail only on a problem the team would refuse to ship. In the software testing life cycle, a required check is an exit criterion. Good candidates have these traits:
- Reliable. The check gives the same result on the same code. A flaky test blocks correct changes at random, so it runs as a report until someone fixes it.
- Always reported. No path or branch filter can skip the workflow. With a merge queue, the workflow also runs on the
merge_groupevent. - Stable in name. Matrix jobs report one check per leg, e.g.
unit (20). A team can require one final job thatneeds:the others, runs withif: always(), and fails unless each succeeded. - Fast. Each change waits for the check, so a slow check becomes a queue for teams using trunk-based development.
- Tied to behavior. At least one required check tests a main user flow end to end, e.g. checkout, not only the build.
Checks whose results need judgment, e.g. AI review comments, work better as reports than as blocking checks.
What are the limits of required status checks?
Required status checks have these limits:
- A pass covers only what ran. The rule reads a name and a result, not the tests behind it. A green
e2echeck says nothing about flows thate2edoes not test. - Skipped work can pass or stall. A job skipped by an
ifcondition reports success, but a workflow skipped by a path filter leaves its check pending. - Checks can pass on a stale base. Without the strict setting or a merge queue, the checks may have tested the branch against an older
main. - Admins can bypass them. A branch protection rule does not apply to admins until someone turns on "Do not allow bypassing the above settings." A ruleset exempts only those on its bypass list.
- They check code, not intent. A change can pass each check and still do the wrong thing, so code review stays part of the merge rule.
How are status checks different from check runs?
A status check on GitHub is either a check run or a commit status. A rule can require either type by name.
GitHub's status checks reference says GitHub Actions creates check runs, not commit statuses. Only a GitHub App can create a check run through the Checks API. They differ on these attributes:
| Attribute | Check run | Commit status |
|---|---|---|
| Created by | A GitHub App, e.g. GitHub Actions | A user or service with write access |
| Result | A status, then a conclusion, e.g. failure | One of error, failure, pending, or success |
| Detail | A summary and line annotations | A short description and a link |
| Grouped in | A check suite for each app and commit | A combined status for the commit |
FAQs
Can an admin merge without the required checks?
Under a GitHub branch protection rule, an admin can merge without the required checks by default. The rule does not apply to admins until its "Do not allow bypassing the above settings" option is on. A ruleset exempts only those on its bypass list, so an admin who is not on it must wait for the checks.
Why is a required check stuck waiting for status?
A required check waits for status when no result with its name reaches the pull request's last commit. A path filter can skip the whole workflow, or a renamed job can report under a name the rule does not list.
What is a GitHub ruleset?
A GitHub ruleset is a named list of rules for branches or tags, e.g. a rule that requires checks to pass. One branch can have several rulesets and a branch protection rule at once, and GitHub applies the strictest version of each rule.
Should a flaky test be a required check?
A flaky test should not be a required check, because it blocks correct changes at random. The team can quarantine it, so it reports without blocking until someone fixes it, then require it again.