Skip to content

OpenAPI Diff — Compare API Specifications and Track Changes

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about OpenAPI Diff. We cover key concepts, practical examples, and best practices to help you master this topic.

OpenAPI diff tools compare two API specifications and report added, removed, and changed endpoints, models, parameters, and security schemes, enabling automated API change management.

What You'll Learn

How to use OpenAPI diff tools to compare specifications, detect breaking vs. non-breaking changes, generate human-readable changelogs, integrate diff checks in CI/CD pipelines, and manage API version evolution safely.

Why It Matters

API consumers depend on contract stability. Breaking changes without notice cause integration failures, downtime, and frustrated developers. Automated diff detection lets you review changes before deployment and communicate exactly what changed. DodaTech blocks deployments if an API diff detects breaking changes without a major version bump.

Real-World Use

A developer updates the Orders API spec to add a required field. The CI pipeline runs OpenAPI diff, flags a breaking change, and prevents the deployment. The developer reviews the diff, decides to make the field optional instead, and re-runs the pipeline.

flowchart LR
    A["Current\nSpec v1"] --> C["OpenAPI\nDiff Tool"]
    B["Proposed\nSpec v2"] --> C
    C --> D{"Breaking\nChange?"}
    D -->|"Yes"| E["Block\nDeployment"]
    D -->|"No"| F["Generate\nChangelog"]
    E --> G["Review &\nFix"]
    G --> B
    F --> H["Deploy &\nNotify"]
    style C fill:#bbf7d0,stroke:#16a34a
    style D fill:#fef3c7,stroke:#d97706
    style E fill:#fecaca,stroke:#dc2626

Installing OpenAPI Diff

# Install openapi-diff CLI (Node.js):
npm install -g openapi-diff
echo "openapi-diff installed"
# Expected output:
# added 42 packages in 3s

# Verify installation:
openapi-diff --version
# Expected output:
# 2.0.1

# Alternative: Java-based OpenAPI Diff:
# java -jar openapi-diff.jar --help

Comparing Two Specs

# Compare two API specifications:
diff_result = """
openapi-diff spec-v1.yaml spec-v2.yaml
"""
print("Running diff...")
# Expected output:
# --- Comparing spec-v1.yaml vs spec-v2.yaml ---
# 
# ## Breaking Changes
# 
# ### Removed endpoints
# - DELETE /api/orders/{orderId} (endpoint removed)
# 
# ### Changed endpoints
# - POST /api/orders
#   * Request body: field 'email' changed from optional to required
#   * Response: removed 'discount' field from 200 response
# 
# ## Non-breaking Changes
# 
# ### Added endpoints
# - GET /api/orders/export (new endpoint)
# 
# ### Added fields
# - POST /api/orders request body: added 'notes' field (optional)
# - GET /api/orders/{orderId} response: added 'shippingDate' field
#
# --- Summary ---
# Breaking: 2
# Non-breaking: 3

Breaking vs Non-Breaking Changes

# spec-v1.yaml (original)
openapi: 3.0.3
info:
  title: Orders API
  version: 1.0.0
paths:
  /orders:
    get:
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Order'
components:
  schemas:
    Order:
      type: object
      required: [id, email]
      properties:
        id:
          type: string
        email:
          type: string
        status:
          type: string
# spec-v2.yaml (proposed change)
# Compare with: openapi-diff spec-v1.yaml spec-v2.yaml
paths:
  /orders:
    get:
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1  # Added validation: non-breaking
        - name: sort
          in: query    # Added parameter: non-breaking
          schema:
            type: string
components:
  schemas:
    Order:
      type: object
      required: [id, email, status]  # status is now required: BREAKING
      properties:
        id:
          type: string
        email:
          type: string
        status:
          type: string

CI/CD Integration

# .github/workflows/api-diff.yml
name: API Diff Check
on:
  pull_request:
    paths:
      - 'specs/openapi.yaml'

jobs:
  api-diff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Install openapi-diff
        run: npm install -g openapi-diff

      - name: Compare specs
        run: |
          git show HEAD~1:specs/openapi.yaml > spec-base.yaml
          openapi-diff spec-base.yaml specs/openapi.yaml > diff-output.txt
          cat diff-output.txt

      - name: Check for breaking changes
        run: |
          if grep -q "Breaking Changes" diff-output.txt; then
            echo "::error::Breaking changes detected!"
            exit 1
          fi
          echo "No breaking changes. Proceeding."

# Expected behavior:
# - On PRs modifying the spec, runs diff against the base branch
# - Outputs the diff report
# - Fails the CI if breaking changes are found

Generating Changelogs

# Programmatic diff with openapi-diff library (Node.js):
import subprocess
import json

def generate_changelog(old_spec, new_spec, output_format="markdown"):
    """Generate a changelog from spec comparison."""
    cmd = [
        "openapi-diff",
        old_spec,
        new_spec,
        "--format", output_format
    ]
    result = subprocess.run(cmd, capture_output=True, text=True)
    return result.stdout

changelog = generate_changelog(
    "spec-v1.yaml",
    "spec-v2.yaml",
    output_format="markdown"
)
print(changelog)
# Expected output (markdown changelog):
# # API Changelog
#
# ## Breaking Changes
# - **DELETE /api/orders/{orderId}**: Endpoint removed
# - **POST /api/orders**: `email` field changed from optional to required
#
# ## Non-breaking Changes
# - **GET /api/orders/export**: New endpoint added
# - **POST /api/orders**: New optional field `notes`

Common Mistakes

1. Ignoring Breaking Changes

A seemingly small change like adding a required field to a response breaks all existing clients that parse the response. Always preserve optional fields when possible and add new fields as optional.

2. Not Running Diff in CI

Manual spec review misses subtle changes. Automated diff in CI catches every modification. Include diff checks in both PR review and deployment pipelines.

3. Misinterpreting Breaking vs Non-Breaking

Adding a new endpoint is non-breaking. Changing an existing endpoint's request or response schema often is breaking. Adding an optional field to a response is non-breaking only if clients ignore unknown fields.

4. Not Versioning Diff Results

Save diff output with each release. This creates an audit trail of API evolution and helps consumers understand what changed between versions.

5. Forgetting About Default Values

Changing a default value for a parameter appears non-breaking but changes behavior for clients that rely on the default. Semantic versioning should consider this a minor change.

Practice Questions

  1. What is the purpose of OpenAPI diff?
  2. How do you identify breaking changes in a diff result?
  3. Why should you run diff checks in CI/CD?
  4. What is the difference between breaking and non-breaking changes?

Answers:

  1. OpenAPI diff compares two API specifications and identifies added, removed, and changed components, classifying each change as breaking or non-breaking.
  2. Breaking changes are listed under the Breaking Changes section of the diff output. Key indicators: removed endpoints, changed parameter requirements, removed response fields, and added required fields.
  3. Automated diff checks in CI catch unexpected changes before deployment, enforce API Versioning policies, generate changelogs automatically, and prevent breaking changes from reaching consumers without review.
  4. Breaking changes require existing clients to update their code to continue functioning. Non-breaking changes are backward-compatible and existing clients work without modification.

Challenge: Set up a GitHub Actions workflow that runs OpenAPI diff on every PR modifying the spec, posts the diff result as a PR comment, and blocks merging if breaking changes are detected. Test it with both a breaking and non-breaking change.

FAQ

Can openapi-diff compare specs across different OpenAPI versions?

Yes. openapi-diff can compare OpenAPI 2.0 specs against OpenAPI 3.0 specs and identify differences despite the structural changes between versions.

What is considered a breaking change in OpenAPI?

Removing or renaming endpoints, changing required fields, removing response fields, changing parameter types, adding required request body fields, and changing security schemes are all breaking changes.

How do I generate a human-readable changelog?

Use the --format markdown flag to output a markdown changelog suitable for release notes. Use --format html for embedding in documentation sites.

Does openapi-diff support OpenAPI 3.1?

Yes. openapi-diff supports OpenAPI 2.0, 3.0, and 3.1 specifications. Some advanced 3.1 features like webhooks and JSON Schema 2020-12 support may be limited.

Can I compare specs programmatically in my code?

Yes. Use the openapi-diff Node.js library or the Java OpenAPI Diff library to compare specs programmatically and process results in your application.

Mini Project

Take an existing API spec, introduce a breaking change (remove an endpoint, add a required field), and a non-breaking change (add an optional field, add a new endpoint). Run openapi-diff to compare, generate a markdown changelog, and verify the breaking change detection works correctly.

What's Next

Version Management — manage API specification versions and evolution.

CI/CD Codegen — integrate Code Generation with CI/CD pipelines.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro