Menu

Topic 2 of 8

Versioning Strategy

Learn Versioning Strategy for free with explanations, exercises, and a quick test (for API Engineer).

Published: January 21, 2026 | Updated: January 21, 2026

Why this matters

Versioning is how you evolve APIs without breaking apps in production. As an API Engineer, you will: ship new features safely, deprecate legacy fields, coordinate multi-service rollouts, and communicate change timelines. A clear versioning strategy reduces outages, support tickets, and client churn.

  • Real tasks you will face: adding fields without breaking mobile clients; removing deprecated endpoints; introducing a new pagination model; evolving protobuf messages; handling GraphQL schema deprecations; setting deprecation and sunset headers; coordinating with SDKs.

Concept explained simply

An API is a contract. Versioning is the rulebook for changing the contract in a predictable way so clients can adapt. Backward-compatible changes flow into the current version; breaking changes require a new version and a migration plan.

Mental model

  • Contract: what the client can rely on (shapes, names, behaviors).
  • Compatibility budget: every change spends budget. Only non-breaking changes are “free”. Breaking changes require a new major version and runway.
  • Migration runway: announce → deprecate → dual-run → sunset.

Versioning options at a glance

  • REST path versioning: /v1/users. Simple, cache-friendly, explicit. Best for clear breaking changes.
  • REST header/content negotiation: Accept: application/vnd.acme.user+json; version=2. Flexible and can avoid path sprawl; requires clients to set headers.
  • REST query param: ?version=2. Easy to try; weaker caching; not ideal for long-term strategy.
  • GraphQL: often “versionless” schema with @deprecated on fields, plus additive changes. For rare breaking changes, use a new graph/schema name (e.g., /graphql/v2) or a major API namespace.
  • gRPC: use protobuf evolution rules. Prefer staying on the same service name with backward-compatible field changes. For breaking changes, create new package or service name (e.g., user.v2) and reserve old tags.

Compatibility policy

  • Change taxonomy:
    • Non-breaking (allowed in current version): adding optional fields, adding enum values (if clients ignore unknown), adding new endpoints/queries, widening constraints, adding defaultable request fields.
    • Breaking (requires new major version): removing/renaming fields; changing field types or semantics; tightening validation; changing pagination, id formats, or error codes in incompatible ways.
  • Semantic versioning for APIs:
    • MAJOR (v1 → v2): breaking changes.
    • MINOR (v1.x): additive, backward-compatible features.
    • PATCH (v1.x.y): bug fixes, docs, performance; no contract change.
  • Deprecation protocol:
    • Mark deprecated: Deprecation: true and Sunset headers for REST; @deprecated(reason) for GraphQL; comments/options in protobuf and release notes for gRPC.
    • Announce date and removal window (e.g., 90–180 days for external clients).
    • Dual-run during migration; monitor usage; then remove.
Header examples for REST
Deprecation: true
Sunset: Fri, 01 Nov 2026 00:00:00 GMT
Link: <https://api.example.com/policies/versioning>; rel="deprecation-policy"
X-API-Version: 1.8
Warning: 299 - "Field 'fullName' is deprecated; use 'name'"

Worked examples

1) Rename fullName → name in REST

Goal: rename response field fullName to name.

  • Non-breaking path: keep fullName, add name. Document fullName as deprecated. Emit Warning header for 60–180 days. Later, remove fullName in v2 path (/v2/users).
  • Rollout steps:
    1. Add name (v1.12). Keep fullName.
    2. Deprecate fullName with headers.
    3. Release /v2/users without fullName.
    4. Dual-run v1 and v2; monitor traffic.
    5. Sunset v1 after adoption threshold.
2) Add optional middle_name

Adding an optional response property is backward-compatible. No new version required. Ensure clients are tolerant of unknown fields. Document the field and update SDKs.

3) Enum evolution: status = {pending, active}

Adding paused is usually non-breaking if clients handle unknown values safely. Recommendations:

  • Document that enum sets are open and clients must handle unknown values.
  • If a client crashes on unknown values, provide a transitional header (e.g., X-Enum-Compatibility: strict) or a compatibility flag until they update.
4) gRPC message evolution
syntax = "proto3";
package user.v1;
message User {
  int64 id = 1;
  string name = 2; // deprecated: use given_name + family_name
  string given_name = 3;
  string family_name = 4;
}
// Rules:
// - Never reuse field numbers. Use 'reserved' for removed fields.
// - Add new fields with new tags; keep them optional.
// - For breaking wire changes, create user.v2 package.

Design checklist

  • [ ] State your default compatibility policy (what changes are safe).
  • [ ] Choose canonical version signal (path or header) and stay consistent.
  • [ ] Define deprecation + sunset window with dates.
  • [ ] Provide migration guidance and examples per change.
  • [ ] Decide on monitoring: how you measure remaining v1 usage.
  • [ ] Document GraphQL deprecation and gRPC protobuf rules.
  • [ ] Plan SDK alignment and sample requests for each version.

Exercises

Do these now. They mirror the graded exercises below and prepare you for the quick test.

  1. Draft a versioning policy for a platform offering REST, GraphQL, and gRPC.
  2. Plan a safe rollout for a breaking change that removes a field and tightens validation.
Need a nudge?
  • Prefer additive changes in-place; reserve majors for truly breaking changes.
  • Use Deprecation/Sunset headers and a dual-run period.
  • For gRPC, never reuse field numbers; use new package for majors.

Common mistakes

  • Mixing version signals (some endpoints in path, some in header) causing confusion. Fix: pick one canonical method per API surface.
  • Declaring a breaking change as minor. Fix: follow your taxonomy; if clients must change code, it is a major.
  • No sunset dates. Fix: always set dates and communicate clearly.
  • Removing deprecated fields too quickly. Fix: use data-driven thresholds and grace periods.
  • Reusing protobuf field numbers. Fix: mark removed tags as reserved.
  • GraphQL hard breaks. Fix: use @deprecated and allow time; consider a new graph name for majors.
Self-check
  • Can you explain which changes are safe vs breaking with one sentence each?
  • Can a client discover the current version and deprecation status from responses?
  • Is there a written removal date and migration example?

Practical projects

  • Build a small REST service with /v1 and /v2 for a users resource. Add Deprecation and Sunset headers and a metrics log for v1 usage.
  • Create a GraphQL schema, deprecate a field, and add a resolver that supports both old and new shapes.
  • Design a protobuf for Orders, simulate adding fields and reserving old tags, then publish a v2 package with a breaking rename.

Quick Test

Available to everyone; only logged-in users get saved progress.

Answer short questions to validate understanding of breaking vs non-breaking changes, version signals, and rollout steps.

Mini challenge

Your API returns price_cents as an integer. You want to return a structured price object with currency and amount. Propose a plan that minimizes client breakage. Include: current version handling, deprecation headers, v2 design, migration guide snippet, and how you will monitor adoption.

Who this is for

  • API Engineers, Backend Engineers, and Tech Leads designing evolvable services.
  • Mobile/web engineers consuming APIs who need to understand server change policies.

Prerequisites

  • Basic HTTP knowledge (methods, status codes, headers).
  • Familiarity with JSON/GraphQL or protobuf messages.
  • Understanding of backward compatibility.

Learning path

  • API style basics → Resource modeling → Versioning strategy (this lesson) → Deprecation & migration → Observability for change rollout.

Next steps

  • Write a one-page versioning policy for your team and share it for review.
  • Identify one upcoming change and classify it as minor or major with rationale.
  • Implement deprecation headers in a staging endpoint and test clients.

Practice Exercises

2 exercises to complete

Instructions

Your company exposes REST (/api), GraphQL (/graphql), and gRPC (internal). Write a concise policy (bulleted) that covers:

  • Canonical version signal for REST and when to use a new major.
  • GraphQL deprecation approach and when to create a new schema name.
  • gRPC protobuf evolution rules and when to create a new package.
  • Deprecation and sunset timelines (dates), and required headers/annotations.
  • Monitoring and rollout steps.
Expected Output
A clear, one-page policy with consistent rules for REST, GraphQL, and gRPC; explicit timelines; concrete headers/annotations; and rollout monitoring.

Versioning Strategy — Quick Test

Test your knowledge with 6 questions. Pass with 70% or higher.

6 questions70% to pass

Have questions about Versioning Strategy?

AI Assistant

Ask questions about this tool