How does Spring Cloud Contract's producer-first workflow differ from Pact's consumer-driven one in who must act?
answer
- One team writes it, the other records it
- Ask whose build turns red first
- Producer's repository versus a published pact
- Stub JAR versus recorded expectations
- Who must chase whom after a failure
basics
~20 sSpring Cloud Contract puts the contract in the producer's repository, so the producer's own build fails first. Pact records the contract from the consumer's tests, so the provider's verification build fails and the provider must chase the consumer.
solid answer
~50 sThe two tools move the obligation to opposite teams. Under **Spring Cloud Contract** a human on the producer side writes the contract file, the producer's build generates tests from it, and a mismatch reddens the **producer's own build** in the same run that compiled the change — nobody else is involved, and the producer decides whether to revert or to change the contract in a reviewable diff. Under **Pact** the consumer's test run records the pact and publishes it, the provider fetches and replays it, and the failure surfaces on the **provider's verification build** — pointing at an expectation the provider never wrote and cannot unilaterally change without talking to the consumer team. So Spring Cloud Contract asks consumers to trust a file they did not author; Pact asks the provider to negotiate, and requires every consumer to keep publishing.
go deeper
Recall the direction of each tool: with Spring Cloud Contract the producer writes the file, with Pact the consumer's test run records it. That single fact answers most screening questions here.
Be ready to trace both pipelines end to end — who authors, where the artefact goes, which build generates tests, and which build shows the failure — and to name the stub JAR and the published pact as the two deliverables.
Expect to argue the obligation asymmetry with a real case: a producer that can fix a break alone versus a provider blocked on another team, and what each tool demands of callers to stay honest.
Own the choice across the estate: language mix, who really designs the APIs, whether callers can participate at all, and which failure mode — a blocked provider or self-flattering producer contracts — your organisation can actually catch.
## Two directions through the same idea Both tools stop a service change breaking a caller, and both do it by generating tests from a machine-readable description of an interaction. Everything interesting is in the direction the description travels. **Spring Cloud Contract is producer-first.** A person on the producer team writes a Groovy or YAML contract file into the producer's repository. The producer's build generates provider tests from it and publishes a stub JAR consumers can run against. **Pact is consumer-driven.** The consumer's own test suite runs against a local mock, and the pact file falls out of that run as a recording of what the consumer actually asked for. It is published to a Pact Broker, and the provider fetches it and replays it against a running instance. ## Who is obliged to act | | Spring Cloud Contract | Pact | |---|---|---| | Who authors the description | a producer engineer, by hand | the consumer's test run, by recording | | Where it lives | the producer's source tree (or a shared contracts repository) | published to a Pact Broker | | Who generates tests from it | the producer's build | the provider's verification run | | Whose build reddens first | the **producer's**, pre-merge, in its own pipeline | the **provider's**, when it verifies | | Who can fix it alone | the producer — revert the code, or edit the contract | nobody: the expectation belongs to the consumer | | What the other team receives | a versioned stub JAR to develop against | a guarantee its recorded expectations still hold | | What the other team must supply | agreement that the contract reflects reality | a live, currently-publishing test suite | The row that decides most arguments is the fifth. A Spring Cloud Contract failure is **inside one team's boundary**: the engineer who broke it can restore the field or change the contract, and the contract edit shows up as a diff a reviewer can challenge. A Pact verification failure is **across a boundary by construction**: the provider is holding an expectation someone else recorded, and the honest resolutions are to keep supporting it, to get the consumer to change and republish, or to make an explicit decision to break them. ## What each demands of the other team Spring Cloud Contract demands two things from consumers, and both are easy to skip: 1. **Review.** A producer-written contract records what the producer *believes* callers need. If no consumer engineer ever reads it, it is fiction with a build failure attached. 2. **Actual consumption.** Consumers must run their tests against the published stub JAR. A stub nobody consumes proves nothing about anyone's client code. Pact demands one thing from consumers, continuously: **keep publishing**. A consumer whose test suite is deleted, disabled or left unrun stops contributing expectations, and the provider's verification quietly gets easier without anyone deciding that it should. ## The consumer you cannot reach Take an archive-digitisation workflow team inside a 23-service estate. Its `scan-service` has 6 known callers. One of them is an internal batch job whose owning team was dissolved 14 months ago: it still runs nightly, still parses the OCR-status payload, and there is nobody to ask and no test suite to run. - Under **Pact**, that caller contributes nothing. There is no recorded expectation, so verification says the provider is free to change a field the batch job depends on. Consumer-driven means exactly that: no consumer, no drive. - Under **Spring Cloud Contract**, the producer writes a contract describing what it believes the batch job needs — reconstructed from logs or a schema — and from then on the producer's own build defends that shape. Nobody else has to exist for it to work. State the limitation with it, because a good interviewer will ask: the producer-written contract encodes a **belief**, not an observed expectation. It is worth having, and it is weaker evidence than a recording. ## Choosing between them - **A polyglot estate.** Pact has consumer libraries across many languages and its pact file is language-neutral JSON. Spring Cloud Contract's test generation targets JVM code and its stubs ship as Maven artifacts, though Stub Runner can be run as a standalone server so a non-JVM caller can still hit the stubs over HTTP. - **A JVM shop where the producer owns the API design.** Spring Cloud Contract fits the grain: the contract reviews like code, and the failure lands where the change was made. - **Callers who genuinely drive the design, or too many to poll.** Pact's recording tells you what is *actually* used, which no amount of producer-side authoring can. - **Callers who cannot participate.** Only the producer-first model can speak for them at all. - **Organisational reality.** Pact's failure mode is a provider blocked on a conversation with another team; Spring Cloud Contract's failure mode is a producer quietly writing contracts that flatter its own design. Pick the failure you are better staffed to catch.
- In a Spring Cloud Contract shop, how do you stop the producer writing contracts no caller actually relies on?Make consumption the evidence, not authorship. Require the consuming team to sign off the contract in the producer's pull request, and require their own CI to run against the published stub JAR. A contract that no consumer build exercises is an unverified belief with a red light attached — track which callers consume which stub versions and treat a gap as a finding.
- Which of the two copes better with a caller written outside the JVM?Pact, generally: consumer libraries exist across many languages and the recorded pact is language-neutral JSON, so the caller participates as a first-class party. Spring Cloud Contract can still serve such a caller — Stub Runner runs as a standalone server, so the stubs are reachable over plain HTTP — but the caller contributes no expectations, only consumes the producer's.
- How are contract files shared when the producer's repository is closed to the consuming team?Spring Cloud Contract supports keeping contracts in a separate repository that the producer's build pulls from at generation time, so the consuming team can raise a pull request against the contract without access to the service code. It costs you an extra moving part and a versioning story, and it buys a review path that would otherwise not exist.
saying these in an interview costs you the question
- Calls Spring Cloud Contract consumer-driven like Pact
- Thinks the consumer authors the Spring Cloud Contract file
- Cannot say whose build fails first in each
- Assumes a producer-written contract proves a caller's need
- Claims Pact works without the consumer publishing anything