Learning · Microservices

Contracts and versioning

How to evolve APIs and events without lockstep releases — compatibility, consumer-driven expectations, and deprecation discipline.

Independent deployability dies the day every consumer must upgrade in the same release train. Contracts are how you avoid that.

Treat interfaces as products

An HTTP API or event schema is a product with users (other services and teams). Breaking it without a migration path is a production incident delayed by a deploy.

Document:

  • what fields mean
  • what is required vs optional
  • compatibility guarantees
  • deprecation timelines

Prefer additive change

Safe evolution is usually additive:

  • add optional fields
  • add new endpoints or event types
  • keep old ones until consumers move

Breaking changes need a plan: dual publish, dual read, feature flags, or a versioned endpoint (/v2) with a kill date.

Events need schemas too

“JSON on a topic” is not a contract. Use a schema registry or equivalent discipline:

  • backward/forward compatibility rules
  • explicit ownership of each event type
  • no silent renaming of fields that already shipped

Consumers should tolerate unknown fields. Producers should not remove fields consumers still rely on.

Consumer-driven clarity

Producers should know who consumes them and for what. Consumer-driven contract tests (or at least tracked consumers) catch breakages before production.

If you cannot list consumers of an event, you cannot safely change it.

Auth and trust are part of the contract

Service-to-service calls need clear identity and authorization for sensitive operations. Treat trust as a first-class concern — see Security for the full picture. “Open on the internal network” is not a contract; it is an incident waiting for a wrong hop.

Senior habit

Before merging an interface change, ask: Can an old consumer and a new producer (or the reverse) run together during rollout? If not, you do not have a rollout — you have a flag day.

← Microservices