Overview

GraphQL diff tool — detect every change, automatically

What the diff engine detects#

Breaking change types#

Field removed from a type · Argument removed from a field · Type changed for a field · Required argument added to a field · Enum value removed · Interface removed from a type · Input field removed · Input field type changed · Input field required added · Directive removed

Non-breaking changes#

New field added to a type · New argument added to a field · New type added · New enum value added · New directive added · Description updated

What is a breaking change in GraphQL?#

In a GraphQL schema, a breaking change is any modification that can cause existing client applications to fail or behave unexpectedly. Unlike REST APIs where endpoints are the primary contract, GraphQL's contract is its strongly-typed schema.

Removing or renaming#

If a client queries for a field that no longer exists, the API returns an error. Renaming is effectively the same as removal from the client's perspective.

Changing a field's type#

Modifying a field from String to Int will cause type mismatch errors client-side.

Altering nullability#

Changing a nullable field (name: String) to non-nullable (name: String!) is a breaking change. If the server ever returns null for that field, it violates the schema contract.

Adding a required argument#

If you add a new required argument to a field, any existing queries that do not provide it will fail validation.

Common GraphQL breaking changes, with examples#

Removing a field. Before:

type User { id: ID! firstName: String! lastName: String! }

After (breaking) — a client querying lastName now receives an error:

type User { id: ID! firstName: String! }

Changing nullable to non-nullable. This seems safe but is a hidden danger — if any existing backend data has a null value for bio, the server is forced to return a field-level error, potentially nullifying the entire parent object.

# Before
type User { id: ID! bio: String }
# After (Breaking)
type User { id: ID! bio: String! }

Adding a required argument. Any client previously calling posts without arguments now fails schema validation.

# Before
type Query { posts(limit: Int = 10): [Post!]! }
# After (Breaking)
type Query { posts(limit: Int = 10, category: String!): [Post!]! }

Why GraphQL needs different tooling than REST#

  • Introspection-based schemas — GraphQL APIs are self-documenting through introspection, providing a more reliable source of truth than a static spec file that could be out of date.
  • Additive-by-design philosophy — GraphQL encourages evolving schemas by adding fields/types rather than changing existing ones, but doesn't prevent breakage entirely.
  • Deprecation as a first-class citizen — The @deprecated directive is best practice; a good governance tool tracks deprecated-field usage and enforces a proper deprecation lifecycle.
  • Complex type system — Interfaces, unions, and input objects mean a single change can have far-reaching ripple effects that a simple text diff cannot trace.

Status#

GraphQL support is coming soon to CodeRifts — the detection engine for OpenAPI (types, breaking-change taxonomy, risk scoring) is live today; GraphQL is being built to the same standard. See OpenAPI support (available now).

Updated

Was this page helpful?