Contract Testing with Pact — Consumer & Provider (2026)
Pact contract testing explained: consumer-driven contracts, provider verification, the broker, and CI wiring that catches microservice breakages before they reach staging.

Last updated 2026-07-20 · 13 min read · By Avinash K
In a microservices world, integration tests scale badly and end-to-end tests scale worst. Consumer-driven contracts with Pact catch cross-service breakages in unit-test time. Every serious platform team runs Pact — this guide gets you productive in an afternoon.
Key takeaways
- What consumer-driven contracts are and why they beat integration tests.
- A consumer test that generates a pact file.
- A provider verification test that fails builds on incompatibility.
- The Pact Broker: publishing pacts and gating deploys with can-i-deploy.
1. Why contract testing
End-to-end tests grow O(n²) with services and go red every deploy. Contracts assert only what the consumer uses from the provider. Consumer-side is fast (a mock server); provider-side runs against the real service. Break the contract, break the build — never in staging.
2. Consumer test — Node.js example
import { PactV3, MatchersV3 } from '@pact-foundation/pact';
import { getOrder } from '../src/orderClient';
const { like, integer } = MatchersV3;
const provider = new PactV3({ consumer: 'web', provider: 'orders-api' });
test('getOrder', async () => {
provider.addInteraction({
states: [{ description: 'order 4211 exists' }],
uponReceiving: 'a request for order 4211',
withRequest: { method: 'GET', path: '/orders/4211' },
willRespondWith: { status: 200, body: like({ id: integer(4211), total: 100 }) },
});
await provider.executeTest(async (mock) => {
const order = await getOrder(mock.url, 4211);
expect(order.id).toBe(4211);
});
});Running this generates pacts/web-orders-api.json — the contract.
3. Provider verification
import { Verifier } from '@pact-foundation/pact';
new Verifier({
provider: 'orders-api',
providerBaseUrl: 'http://localhost:3000',
pactBrokerUrl: 'https://broker.example.com',
publishVerificationResult: true,
providerVersion: process.env.GIT_SHA,
stateHandlers: {
'order 4211 exists': async () => { await seedOrder(4211); },
},
}).verifyProvider();The verifier replays each interaction against the real service. If the provider changed the response, the build fails with a precise diff.
4. Pact Broker + can-i-deploy
# Publish from consumer CI
pact-broker publish pacts --consumer-app-version=$GIT_SHA --tag=main
# Gate provider deploy
pact-broker can-i-deploy --pacticipant=orders-api \
--version=$GIT_SHA --to-environment=productionThe broker stores every pact + verification. can-i-deploy blocks a deploy if any consumer's verified version is incompatible. See the official Pact docs.
5. When contracts beat other approaches
| Situation | Best fit |
|---|---|
| Two internal services owned by 1 team | Integration tests |
| Many services, many teams | Contracts (Pact) |
| Third-party you cannot control | Recorded HTTP + monitoring |
| End-user flows across all services | Small suite of E2E on top of contracts |
Combine Pact with REST Assured or Postman for regression, and see our API testing interview prep for contract-testing questions asked at senior interviews.
Contract tests are one layer of a wider plan. Our microservices testing strategy shows where Pact sits alongside component, integration, and end-to-end coverage so you don't duplicate the same assertion at four levels.