Quickstart¶
In this tutorial you write a contract, check it and use it to catch a
breaking change. It takes about five minutes. A
contract is one file, pacto.yaml. Everything here
runs on your machine, with no account and no registry.
1. Install Pacto¶
Installation covers the other ways to install and what to do if the script fails.
2. Create a contract¶
Run this from an empty directory and stay there through step 5; step 6 moves inside my-service.
This writes three files: pacto.yaml (the contract), interfaces/openapi.yaml (a placeholder API spec) and configuration/schema.json (a placeholder config schema). The argument is the folder to write into, and its last part becomes service.name, so pacto init fleet/checkout writes a contract for checkout in fleet/checkout. Run pacto init in a folder that already holds a service and it reads the Dockerfile and Kubernetes files instead: see Pactify a service.
Edit my-service/pacto.yaml and set service.version: 1.0.0. Then replace my-service/interfaces/openapi.yaml with an API that has required response fields:
openapi: "3.0.0"
info:
title: my-service
version: 1.0.0
paths:
/orders/{id}:
get:
summary: Get an order
responses:
"200":
description: OK
content:
application/json:
schema:
type: object
required: [id, total]
properties:
id:
type: string
total:
type: number
3. Validate¶
Validation checks three things: the file's shape, that fields agree with each other (a field that names an interface must name one the contract declares, for example) and your policies, the rules your platform team may set for every contract. See the Contract Reference for the full rules.
4. Add consumers¶
Two services depend on my-service, each with a different compatibility range. Copy the folder twice and declare the dependencies:
In checkout/pacto.yaml, set service.name: checkout and replace the dependencies: block that pacto init wrote as comments with:
In reporting/pacto.yaml, set service.name: reporting and use a wider range:
checkout accepts ^1.0.0 (1.x only), reporting accepts >=1.0.0 (1.x and above). Step 7 shows what that difference changes.
5. Introduce a breaking change¶
Copy my-service to v2 and delete the total field from the response schema:
In v2/pacto.yaml, set service.version: 2.0.0. In v2/interfaces/openapi.yaml, remove total from required and from properties so the schema becomes:
6. Diff the two versions¶
Move into my-service and compare the original contract against v2:
$ cd my-service
$ pacto diff . ../v2
Classification: BREAKING
Required bump: major
Changes (3):
[NON_BREAKING] service.version (modified): service.version modified [1.0.0 -> 2.0.0]
[BREAKING] openapi.paths[/orders/{id}].methods[GET].responses[200].content.application/json.schema.properties.total (removed): openapi.paths[/orders/{id}].methods[GET].responses[200].content.application/json.schema.properties.total removed [- map[type:number]]
[BREAKING] openapi.paths[/orders/{id}].methods[GET].responses[200].content.application/json.schema.required[total] (removed): openapi.paths[/orders/{id}].methods[GET].responses[200].content.application/json.schema.required total removed [- total]
breaking changes detected
$ echo $?
1
The classification is BREAKING, so the next published version must be a new major version, and the exit code is 1. That is the CI gate: pacto diff exits non-zero when the change is breaking for anyone who may use the service (pacto impact below says which consumers), so a branch-protection rule that requires passing checks blocks the merge.
7. Find the affected consumers¶
pacto impact takes that diff, finds every service that depends on my-service and tells you which ones break:
$ pacto impact . ../v2 --local ..
Impact: my-service 1.0.0 -> 2.0.0
Classification: BREAKING
Breaking changes: 2
Potentially breaking changes: 0
Affected consumers (2):
checkout direct confidence=contractual compat=incompatible owner=my-team
reporting direct confidence=contractual compat=compatible owner=my-team
note: the range >=1.0.0 has no upper bound, so compatible only means the range >=1.0.0 accepts 2.0.0; this change is BREAKING, so check that reporting does not use what it removes or changes
Release gate: unverified
unverified: the change is BREAKING and 2 consumers depend on my-service, but none is shown to be both incompatible and running. Review each consumer, and add a source that knows where services run (for example --target-state) to tell deployed impact apart
checkout and reporting declare the same edge to the same service and get opposite verdicts. checkout pins ^1.0.0 (1.x only) and breaks. reporting accepts >=1.0.0 (any major), so its range still matches. The note says what that match does not prove: that reporting avoids what the change removes. Pacto tells the two apart because each contract carries its compatibility range.
The exit code is 2: the gate is unverified. The bundles say nothing about where the consumers run, so Pacto neither blocks the change nor calls it safe. Release gate and exit status explains the three outcomes.
owner=my-team is the placeholder team pacto init wrote. confidence=contractual
means the answer comes from the declared ranges alone, without a runtime
observation of the call. direct means each consumer declares my-service itself.
Optional: publish to a registry¶
The steps above need no registry. To see the full round trip, start a local registry and push the contract:
docker run -d --rm -p 127.0.0.1:5001:5000 --name pacto-registry registry:3
pacto push oci://localhost:5001/demo/my-service-pacto -p .
Port 5001 because macOS binds 5000 for AirPlay. 127.0.0.1: because the registry accepts anonymous writes.
Read it back without pulling:
Or pull the bundle:
Clean up:
For a real registry like GHCR, you need pacto login with a personal access token. See Installation for the supply-chain guarantees and Put it in your repository for what to commit.
What's next¶
| Goal | Guide |
|---|---|
| Let Pacto check every release of a real service | Pactify a service |
| Put it in your repository | Put it in your repository |
| Understand every contract field | Contract Reference |
| See contracts for real services | Examples |
| Explore contracts visually | Run pacto dashboard or pacto tui |
| Check what a running service does on the network | Runtime conformance |
| Check a service in CI or on your laptop | pacto run |
| Check every service on a Docker host or server | pacto agent |
| Runtime compliance in Kubernetes | Kubernetes Operator |