Evolving a schema without versions

GraphQL · Advanced · 12 min

GraphQL APIs are expected to evolve continuously instead of shipping /v2.

GraphQL APIs rarely version their endpoint. Instead the schema evolves continuously, relying on one fact: clients receive only the fields they ask for, so adding is safe.

Safe changes: new types, new fields, new optional arguments, new enum values (if clients handle unknown values). Breaking changes: removing or renaming fields, making a nullable field non-null in input positions, making an output field nullable (clients may not expect null), adding a required argument.

Removing things politely:

  • Mark it @deprecated(reason: "Use fullName"). Introspection exposes this, and IDEs strike it through. Since the September 2025 spec edition, deprecation also applies to arguments and input fields.
  • Measure usage. Field-level usage reporting (Apollo GraphOS, Hive and others) tells you when nobody requests it anymore.
  • Remove it once traffic is zero, and use schema checks in CI to catch accidental breaks.

Input design got a new tool in the September 2025 spec: OneOf input objects. input UserBy @oneOf { id: ID email: String } requires exactly one field to be set, replacing ad-hoc validation and enabling input-union style arguments.

Design for the client: name fields after domain concepts rather than database columns, prefer specific fields to generic JSON blobs, and avoid exposing internal IDs or implementation details you might want to change.

Example

type User {
  id: ID!
  fullName: String!
  name: String @deprecated(reason: "Use fullName")
}

"Look a user up by exactly one key"
input UserBy @oneOf {
  id: ID
  email: String
  handle: String
}

type Query {
  user(by: UserBy!): User
}

# Valid:   user(by: { email: "ann@example.com" })
# Invalid: user(by: { id: "1", email: "ann@example.com" })

Remember

  • Adding fields is safe because clients select what they need
  • Deprecate, measure usage, then remove
  • @oneOf inputs require exactly one field
  • Run breaking-change checks in CI

Watch out for

  • Changing a field's type in place instead of adding a new field and deprecating the old one.

Check yourself

  1. Which change is breaking for existing clients?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: graphql.org/learn/schema-design/