On this page
- What you need
- Step 1: add the workflow
- Step 2: decide what fails the job
- One failure fail-on does not control
- Step 3: open a pull request and read the output
- If specs must not leave your runners
- Step 4: tune it
- Step 5: what to do with the output
- Where Graphwake fits
- When the oasdiff Action alone is enough
- Next steps
- Questions
What you need
- A GitHub repository with an OpenAPI 3 spec committed to it. The examples use
openapi.yamlin the repository root; change the path to yours. - If your spec is generated from code, a build step that writes it to a file first. The action compares files, not code.
- Nothing else: the free actions run the oasdiff CLI inside your runner, with no account and no token.
The repository oasdiff/oasdiff-action holds several actions, one per folder. This guide uses breaking. The others:
| Action | What it does | Fails the job |
|---|---|---|
oasdiff/oasdiff-action/breaking@v0 | Breaking changes (errors and warnings), as annotations on the pull request | Only with fail-on |
oasdiff/oasdiff-action/changelog@v0 | Every change that can affect clients, breaking or not | No fail-on input |
oasdiff/oasdiff-action/diff@v0 | The full diff, including description-only edits | Only with fail-on-diff: true |
oasdiff/oasdiff-action/validate@v0 | Checks one spec against the OpenAPI rules | On errors by default |
As read on the action’s README and action.yml files on 2026-11-09 (latest release v0.1.23). @v0 is a moving tag that follows every stable v0.x.y release; pin a release tag if you want to choose when to upgrade.
Step 1: add the workflow
Create .github/workflows/oasdiff.yaml with the README’s quick start:
name: oasdiff
on:
pull_request:
branches: [ "main" ]
permissions:
contents: read
pull-requests: write
jobs:
breaking-changes:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- run: git fetch --depth=1 origin ${{ github.base_ref }}
- uses: oasdiff/oasdiff-action/breaking@v0
with:
base: 'origin/${{ github.base_ref }}:openapi.yaml'
revision: 'HEAD:openapi.yaml'
fail-on: WARN
github-token: ${{ github.token }}openapi.yaml with your spec’s path in both places.on: pull_request
Runs on every pull request into
main. To skip pull requests that do not touch the spec, addpaths: [ "openapi.yaml" ]underpull_request.permissions
contents: readto check out the code.pull-requests: writelets the action post the review link as a pull request comment. Without it, the link goes to the job summary instead.actions/checkout, then git fetch
Checkout gives you the pull request. The
git fetch --depth=1line fetches only the base branch, so the action can read the old spec from git. A full history (fetch-depth: 0) is not needed.base and revision
Both use oasdiff’s
<git ref>:<path>syntax: the spec on the base branch, and the spec in the commit being tested. Each also accepts a plain file path or an http(s) URL.fail-on
Decides whether the job fails. Step 2 covers it. Leave it out and the action only reports.
github-token
The token used to post the review link as a comment. On pull requests from forks the token is read-only, so the link falls back to the job summary.
Step 2: decide what fails the job
oasdiff sorts each breaking change into a level: error (a client that followed the old contract can stop working), warning (it might; a human should look) and info (shown by changelog, not by breaking). fail-on picks the lowest level that fails the job:
| fail-on | Job fails when | Use it when |
|---|---|---|
| Not set (the default) | Never because of a change found | You are trying the action out, or the check should inform and not stop anyone |
ERR | There is at least one error | You want a hard stop on changes oasdiff is sure about |
WARN | There is at least one error or warning | Every possible break needs a decision before the merge (the quick start’s choice) |
One failure fail-on does not control
If oasdiff cannot run at all, the step fails whatever fail-on says: a spec that does not parse, a file missing on one side, an external $ref it is not allowed to load. oasdiff exits with 2 or higher there, and the action passes that on. For a check that must never fail the job, add continue-on-error: true to the step as well; the non-blocking setup shows it.
Step 3: open a pull request and read the output
Change the spec on a branch and open a pull request. The examples below come from a sample openapi.yaml where the pull request makes a new query parameter region required on GET /orders, removes the old limit parameter, and drops the required status field from the GET /orders/{id} response.
1. Annotations on the pull request
The action makes a second oasdiff pass with --format githubactions. GitHub turns each line into an annotation on the Files changed tab and in the run’s summary, titled with the oasdiff rule ID:
::error title=new-required-request-parameter,file=openapi.yaml,line=24,col=12::in API GET /orders added the new required `query` request parameter `region`
::error title=response-required-property-removed,file=openapi.yaml::in API GET /orders/{id} removed the required property `status` from the response with the `200` status
::warning title=request-parameter-removed,file=openapi.yaml::in API GET /orders deleted the `query` request parameter `limit`An added parameter has a line in the new file, so its annotation sits on that line. A removed field or parameter has no line in the new file, so its annotation has no position and GitHub shows it at the top of the file. Read the run summary as well as the diff view.
2. The full report
The step output breaking holds only the first line, the count (No breaking changes when there are none). For the whole report, set output-to-file: oasdiff-breaking.txt and upload that file as an artifact, or run the CLI locally:
3 changes: 2 error, 1 warning, 0 info
error [new-required-request-parameter] at openapi.yaml
in API GET /orders
added the new required `query` request parameter `region`
error [response-required-property-removed] at openapi.yaml
in API GET /orders/{id}
removed the required property `status` from the response with the `200` status
warning [request-parameter-removed] at openapi.yaml
in API GET /orders
deleted the `query` request parameter `limit`
This is a warning because some clients may return an error when receiving an unexpected parameter. It is recommended to deprecate the parameter first.oasdiff breaking main:openapi.yaml HEAD:openapi.yaml on the sample branch, oasdiff 1.34.1.3. The side-by-side review link
When there are breaking changes, the action uploads the two specs to oasdiff.com and posts a link to a side-by-side review in the job summary, and as a comment when the token allows. The specs are encrypted in CI first and the key stays in the link, so the server cannot read them; the link expires after 7 days. The URL is also the step output review_url.
If specs must not leave your runners
Set review: false. Nothing is uploaded and no comment is posted; the detection and the annotations work the same.
Step 4: tune it
Keep settings in a .oasdiff.yaml file in the repository root instead of in each workflow. The actions read it after checkout; inputs set in the workflow’s with: win over the file.
# .oasdiff.yaml (repository root)
fail-on: ERR
err-ignore: ./oasdiff-err-ignore.txtfail-on and err-ignore are keys from the README’s example. severity-levels (also there) raises or silences single rules.When a breaking change is intended and agreed, an ignore file stops it from failing every later run. Each line is the method and path, then the change text as oasdiff printed it (warn-ignore does the same for warnings):
# oasdiff-err-ignore.txt: one accepted breaking change per line, with the PR that accepted it
# PR #1290: region is required from v2; the two known callers already send it
GET /orders added the new required `query` request parameter `region`region change on the sample branch; the other two still show.Two more inputs worth knowing. allow-external-refs is false in the action (the CLI’s default is true), so an untrusted pull request cannot make the runner fetch URLs; set it to true if your spec is split across files or references external URLs. composed: true compares many spec files at once; the side-by-side review is not available in that mode.
Step 5: what to do with the output
A red job tells the author something broke. It does not tell anyone what to do next. For each finding:
Error: look for an additive change first
Many errors have a non-breaking version: a new optional parameter instead of a required one, a new field next to the old one, a new endpoint or version. Ask for that first.
Error you keep: name who calls the endpoint
If the change has to break, list the teams that call the endpoint and tell them before the merge, with what changes and when. Then add the line to the ignore file in the same pull request, so the reason is in the history.
Warning: decide and write it down
request-parameter-removedis breaking only if the server rejects input it does not know. Check, and put the answer in the pull request description.No breaking changes: still read the changelog
New endpoints and fields do not break anyone, but consumers may want them. The
changelogaction lists them.
The reviewer’s side of this, with a copyable pull request template, is the API breaking change checklist for pull requests. What each rule ID means, with before/after snippets, is in OpenAPI breaking changes.
Where Graphwake fits
The action answers “what changed?” in the pull request. Step 5’s hardest line, “list the teams that call the endpoint”, is not in the spec. Graphwake keeps that list for you: its CI step checks the spec on every pull request, and Graphwake tells the teams that call each changed endpoint.
Breaking first, quiet by default
Breaking changes alert, and removed endpoints and response fields always do. Additions stay quiet unless a team opts in.
Who is affected, per endpoint
Consumer teams subscribe to the endpoints they call. The affected teams come from that map, not from memory.
Told while it is still a pull request
With alerts on open pull requests turned on in settings, the subscribed teams hear about a breaking change before the merge, in Slack, Microsoft Teams or email.
Runs next to the action
Graphwake’s CI step sends the spec and never fails or blocks a build, so the oasdiff Action can keep its own
fail-on.
When the oasdiff Action alone is enough
- Every caller of the API is in the same repository, so the pull request’s reviewers are the people who need to know.
- You want the merge to stop on a breaking change:
fail-ondoes that, and oasdiff Pro adds approval per change. - You only need a diff and a changelog. The free actions cover that, with no account.
Next steps
- Run the check without ever failing a build, in GitHub Actions or GitLab CI: OpenAPI diff in CI.
- Route the alert once you know who to tell: API breaking change alerts.
- Compare the two tools: oasdiff vs Graphwake.
Questions
What is the oasdiff GitHub Action called?
It is a repository of actions: oasdiff/oasdiff-action/breaking@v0 for breaking changes, plus changelog, diff and validate under the same path, all in the oasdiff/oasdiff-action repository.
Does the oasdiff Action fail the build on a breaking change?
Only if you set fail-on (ERR or WARN). Without it, the action reports and passes. It still fails if oasdiff cannot run, for example on a spec that does not parse.
Does the oasdiff Action send my spec anywhere?
By default, when it finds changes, it uploads both specs to oasdiff.com encrypted, for the side-by-side review link; the server cannot read them. Set review: false and nothing leaves the runner.
Can I ignore a breaking change we agreed on?
Yes. Put the method, path and change text in a file and pass it as err-ignore (errors) or warn-ignore (warnings), in the workflow or in .oasdiff.yaml.
Is the oasdiff Action free?
The breaking, changelog, diff and validate actions are free and need no account. oasdiff Pro adds per-change approval and a merge gate.
Pick an endpoint. See who it reaches. 7-day free trial. Cancel before day 7 and you pay nothing.
Start free trialSources and last verified
- github.com/oasdiff/oasdiff-action
- github.com/oasdiff/oasdiff-action/blob/main/breaking/action.yml
- github.com/oasdiff/oasdiff/blob/main/docs/BREAKING-CHANGES.md
- github.com/oasdiff/oasdiff/blob/main/docs/GIT-REVISION.md
- oasdiff and its name belong to its authors. Graphwake is not affiliated with the oasdiff project.
Sources checked on 2026-11-09.