Hard20 minDistributed Systems
UpdatedAug 6, 2026
Edit

GraphQL Schema Evolution

Question Variations

  • "Why can adding an enum value be a breaking change?"
  • "How do you migrate a GraphQL field to a new type?"
  • "When is it safe to remove a deprecated field?"
  • "How does non-null error propagation affect schema changes?"

Why This Is Asked

This evaluates whether a candidate can change a GraphQL contract while many independently released clients still depend on it. It focuses on nullability, deprecation, schema telemetry, and safe migrations rather than simply adding fields.

Key Concepts

  • Additive changes: New optional fields and enum values can still affect clients that assume a closed set of values.
  • Deprecation workflow: Mark obsolete fields with a reason, ship a replacement, measure usage, then remove deliberately.
  • Nullability: Tightening or loosening nullability affects error propagation and client code generation contracts.
  • Input safety: Add optional input fields; avoid changing a field’s type or making an existing optional input required.

Question Variations

  • “Why can adding an enum value be a breaking change?”
  • “How do you migrate a GraphQL field to a new type?”
  • “When is it safe to remove a deprecated field?”
  • “How does non-null error propagation affect schema changes?”

Answers by Technology

+ Add Variant
System DesignImprove this answer ✏️

Expected Answer

GraphQL schemas are usually evolved through additive changes. Add a replacement field, document it, mark the old field with @deprecated, and use operation telemetry to determine whether active clients have migrated before removing it. Never assume GraphQL’s client-selected fields make every addition harmless: adding an enum value can break generated exhaustive switches, and changing nullability affects both generated types and error propagation. Avoid changing an existing field’s type or making an optional input required; introduce a new field or input member instead.

Deprecation needs governance. A deprecation reason should say what to use instead, schema checks should reject breaking changes unless approved, and persisted-query or field-usage metrics should identify clients still selecting the old field. For a type migration, expose newPrice beside the legacy price, populate both while clients migrate, then remove the legacy field only after the announced window. Be especially careful with non-null fields: an error resolving one can null an enclosing response path, so a non-null promise must be operationally reliable.

Why It Matters

Schema changes deploy faster than many clients update. A disciplined migration path lets teams improve contracts without unexpected application crashes or partial response failures.

Example Code

type Product {
  price: Int @deprecated(reason: "Use priceMoney")
  priceMoney: Money!
}

type Money { amount: Int!, currency: String! }

Common Mistakes

  • Removing a deprecated field immediately: Deprecation is documentation, not proof that all independently deployed clients have migrated.
  • Adding an enum member without warning clients: Exhaustive client switches can throw or render an invalid state on a new value.

Follow-up Questions

  • Why can a nullable-to-non-null change break clients? (Answer: Existing data or resolver failures may produce null, and the client type contract changes.)
  • How do persisted queries help migration? (Answer: They provide a finite, observable set of server-known operation documents.)

Related Questions

References