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
@deprecateddirective 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).