How it works
The explanation, with examples you can run.
Safe and breaking changes
| Usually safe | Breaking |
|---|---|
| Add a type, field, or enum value* | Remove or rename a field, type or enum value |
| Add an optional argument or input field | Add a required argument or input field |
| Make an argument optional | Make an argument required, or change its type |
| Make an output field non-null | Make an output field nullable |
| Deprecate anything | Change what a field means while keeping its name |
*A new enum value can surprise clients that switch exhaustively over an output enum; give them a default branch. The direction of nullability flips between inputs and outputs: a non-null output promises more (safe), a non-null input demands more (breaking).
Deprecation
type User { id: ID! name: String! fullName: String @deprecated(reason: "Use `name`. Removed after 2027-01-31.")} type Query { users(first: Int, limit: Int @deprecated(reason: "Use `first`.")): UserConnection!} enum Status { ACTIVE DISABLED BANNED @deprecated(reason: "Use DISABLED with a `reason` field.")}The October 2021 edition of the spec allowed @deprecated on fields and enum values; the September 2025 edition also allows it on arguments and input fields, as in limit above. Deprecated elements still work, are hidden from introspection unless the client asks with includeDeprecated: true, and are flagged by editors and linters.
Removing with evidence
The loop is: add the replacement, deprecate the old field with a reason and a date, tell client owners, then measure. Servers can record which fields each operation selects; a registry of persisted or trusted documents tells you exactly which shipped clients use what. When usage reaches zero (or the remaining callers have been contacted and the date has passed), remove the field. Mobile apps make this slower, because old versions stay installed for months.
Automate the check. On every schema change in CI, compare the new schema with the old one, list breaking changes, and test them against the operations clients have registered. That is contract testing with the schema as the contract: the change fails the build, not a customer's app.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.