How does a Pact message contract differ from a schema-registry compatibility check on the same event?
answer
- One compares types, one compares behaviour
- Who does each check represent?
- Schema unchanged, payload quietly emptied
- Some readers publish no pact at all
- Replayed archives sit in no pact
basics
~20 sA registry compatibility check compares schema versions structurally and represents no particular reader. A message pact compares the payload a producer actually emits against one named consumer's executed handler, so it catches semantic breaks the schema still permits.
solid answer
~40 sThe registry compares a **new schema version against previously registered versions** under a structural rule; it does not know which fields anyone reads, or what values are emitted. A message pact compares the **payload the producer actually emits** against the expectation of one named consumer whose real handler ran against it. So a change can be schema-clean and pact-breaking — a field still declared but no longer populated, a new variant a handler branches on, a unit changing from minutes to seconds — and it can be pact-green and registry-refused, because the rule protects readers no pact represents: services that publish no pact, and archived events replayed later. Neither subsumes the other: pacts cover known readers deeply, the registry covers unknown and historical readers shallowly.
code
json · 12 lines{
"beforeRefactor": {
"donorId": "40817",
"bookedAt": "2026-03-11T09:24:00Z",
"centreCode": "BR-217"
},
"afterRefactor": {
"donorId": "40817",
"bookedAt": "2026-03-11T09:24:00Z",
"centreCode": null
}
}go deeper
Recall that a schema check and a contract test are different things: one looks at the schema document, the other runs real consumer code against a real payload.
Be able to state what each check compares and give one concrete change that slips past the schema rule while breaking a consumer, such as a still-declared field that stops being populated.
An interviewer expects both directions with examples, plus the honest limit: a pact suite says nothing about consumers that publish no pact or about events replayed from archive.
Own the policy for the estate: which event streams justify both guards, how you handle readers nobody can contact, and how you stop teams treating a green pact wall as coverage of the whole audience.
## Two checks that compare completely different things Both a schema-registry compatibility check and an asynchronous message pact are described as "making sure the event does not break". They compare different objects, on behalf of different parties, at different moments. | | Registry compatibility check | Asynchronous message pact | | --- | --- | --- | | What is compared | a new schema version against previously registered versions of that schema | the payload the producer actually emits against one consumer's recorded expectation | | Who is represented | no particular reader; the rule is structural | one named consumer, whose real handler ran against that payload | | When it runs | when a schema is registered or checked in CI | on the producer's verification build, per recorded interaction | | What it proves | the schema change obeys the configured structural rule | this producer's output still satisfies this consumer's code | | Blind to | which fields anybody reads, and what values are emitted | any consumer that publishes no pact, and any archived event | The registry is reasoning about **types**. The pact is reasoning about **behaviour**: a handler was executed and it worked. ## Why passing one says nothing about the other Both directions occur, and both are worth being able to narrate. **Schema-clean, consumer-broken.** The schema is untouched, so the registry has nothing to complain about — but the producer's behaviour changed: - A field is still declared and still permitted to be absent or empty, and a refactor quietly stops populating it. Every reader that depended on it fails at runtime. - An event type gains a new variant value in an existing field, and a consumer that branches exhaustively on that field falls through to an error path. - The units or meaning of a field change — minutes become seconds, a local time becomes UTC — without any structural change at all. - Two fields that used to be mutually consistent stop being so. None of these is a schema change; all of them are contract breaks, and a message pact that ran a real consumer handler against a real emitted payload is the thing that catches them. **Pact-green, registry-refused.** Every current consumer's pact stays green because none of them reads the field being removed, yet the registry's configured rule refuses the change — because the rule protects readers the pact suite has never met: services that publish no pact, readers of a long-retention or compacted topic replaying months of archived events, or an external consumer outside the organisation. Here the registry is right and the pact suite is simply silent. ## The uncontactable consumer The gap is easiest to feel with a real shape. A blood-donation scheduling service publishes a slot-booked event to **9 consuming services**. Six of them publish message pacts. Of the remaining three, one is a long-lived reporting job whose owning team was reorganised away — there is nobody to ask what it reads, and no test of it in any pipeline. For those three, the pact suite offers nothing at all: no pact means no recorded expectation and no verification failure, only silence. The registry rule is the only automated guard they have, and it guards them structurally — it will refuse a change that removes or retypes a field, without knowing whether anybody cared. Meanwhile, for the six that do publish pacts, the registry rule is the weaker of the two guards: it would happily accept the producer emptying a field it still declares. So the two are not redundant and neither subsumes the other: 1. **Pacts cover known readers deeply** — they know which fields are actually consumed and whether the handler still works. 2. **The registry covers unknown and historical readers shallowly** — it knows nothing about consumption, but it applies to everyone, including readers you cannot enumerate and events already written to disk. ## When a team genuinely needs both Run both when at least one of these is true, and be honest that otherwise one may be enough: - Events are **durable and replayed** — archived data must stay readable by new code, which pacts never look at. - There are **consumers you cannot enumerate or contact**, as above. - The payload is **encoded** (Avro, Protobuf) rather than self-describing JSON, so structural rules have real teeth. - The fan-out is large enough that a semantic break costs more than the pact suite costs to run. A small internal topic with two consumers who sit in the same team can reasonably run pacts alone. A public, long-retention event stream with unknown readers arguably needs the structural rule more than it needs pacts. ## In an interview Give the one-line distinction first — the registry compares schema versions and represents no particular reader; a message pact compares emitted payload against one named consumer's executed handler — then give one concrete example in each direction. The emptied-but-still-declared field is the sharpest, and the consumer nobody can contact is the sharpest argument for keeping the structural rule even in a mature pact suite.
- Give a change a message pact catches that a schema check cannot.A field that stays declared and permitted to be empty, but that a refactor stops populating. Structurally nothing changed, so a schema rule sees no difference. A consumer's message pact recorded that field present because its handler read it, so provider verification fails on the producer's own build.
- When would you keep only the schema check and drop message pacts for an event?When the readers are unknown or unreachable and no consumer can publish a pact — a public or long-retention stream, or a topic whose consumers sit outside your organisation. There is nobody to record an expectation, so the structural rule is the only guard available, and it at least protects archived events and future readers.
- Do you need both for a small internal event with two consumers in one team?Usually not. If both consumers publish pacts, both are verified on the producer's build, and the events are not replayed from long retention, the pacts already cover the readers that exist. Adding a structural rule buys little beyond documentation, and it is honest to say so rather than defaulting to both.
saying these in an interview costs you the question
- Says a passing schema check means no consumer can break
- Treats message pacts as covering readers that publish none
- Assumes one check makes the other redundant
- Ignores replayed or archived events entirely
- Believes structural rules see which fields are read