Two services that become independent deployments need a plan for changing their interface without a coordinated release. Additive changes are safe; removals and type changes are not. Versioning and contract tests make the boundary explicit instead of accidental.
Before you start
You should understand REST or RPC APIs, and event-driven systems help. This article covers interface evolution; it assumes separate deploy pipelines.
Step-by-step walkthrough
Step 1: Prefer additive changes
Adding an optional field, a new endpoint, or a new event type does not break existing consumers, so treat these as backward compatible and ship them without a version bump. Consumers must ignore unknown fields, which is the tolerance side of the same rule.
Step 2: Version deliberately when you must break
A breaking change needs a new version, whether in the URI (/v2/orders), a media type, or a message header. Run the old and new versions side by side and let consumers migrate. A version is a contract with a date, not a vanity number.
Step 3: Deprecate with evidence
Publish a deprecation timeline, add a Sunset header, and track per-consumer usage so you know who still calls the old version. Remove the old version only after usage reaches zero, not on a guess.
Worked scenario
An additive field keeps the existing consumers working.
{
"id": "o-1",
"total": 42,
"currency": "USD",
"giftWrap": false
}Walk through the example
giftWrap is a new optional field, so a consumer that predates it simply ignores it and continues reading id and total. Renaming total, by contrast, would break every consumer, so it would belong in a new version. The additive rule keeps the fleet moving without lock-step deploys.
Common mistake
Making a breaking change and assuming “no one uses that field”; without usage telemetry the assumption is a guess. Another is versioning events implicitly by changing their schema in place, which silently breaks every stored and queued message.
Verify the behavior
Run consumer-driven contract tests against the provider for each consumer and fail the build on a breaking diff. Assert that consumers tolerate unknown fields by adding one and re-running their tests. Track old-version usage and confirm it reaches zero before removal.
Interview exercise
You must rename a widely used field. What is the safe path?
Answer and reasoning
Add the new field alongside the old one, have consumers migrate to the new name, and keep both in sync for a deprecation window. Publish the timeline and sunset the old field once usage drops to zero. Only if that window is impossible do you cut a new version and run it in parallel, because a rename in place is a breaking change for every consumer at once.
Continue learning
Compare contract strategy in Contract evolution and Contract testing. Read the Google API design guide and try the Microservices interview questions.