Pact Broker vs PactFlow for Small Teams
When you move beyond sharing pact files on a shared drive and need reliable can-i-deploy gates in CI, you have to pick a broker. The choice is between running the open-source Pact Broker yourself and paying for the managed PactFlow SaaS. This guide is part of Consumer-Driven Contracts with Pact and is aimed at small engineering teams — typically 2–10 engineers, 3–15 services — deciding which path to take.
The short version: the open-source broker is production-ready and free, but you own the infrastructure. PactFlow removes all operational overhead and unlocks bi-directional contract testing and enterprise features, at a monthly cost. The decision turns on three variables: how much CI reliability you can afford to trade for ops savings, whether you need bi-directional contracts, and what your monthly SaaS budget looks like.
When Each Fits
Use the self-hosted Pact Broker when
- Your team is already comfortable running Docker-based infrastructure (a Postgres-backed container is all you need).
- You operate in a regulated environment that prohibits sending contract data to a third-party SaaS — on-prem or VPC-isolated deployments are straightforward.
- Your budget for tooling SaaS is near zero and you can absorb a few hours per quarter of maintenance.
- Your integration surface is HTTP consumer-driven contracts only — you do not need bi-directional testing of existing OpenAPI specs against real provider responses.
- The team is small enough that a single shared broker token is acceptable; you do not need per-team RBAC or SSO.
Use PactFlow when
- You want zero operational overhead: no Docker to maintain, no Postgres to back up, no upgrade windows to plan.
- Your team needs bi-directional contract testing — uploading an OpenAPI spec as a provider-side contract and having PactFlow compare it against consumer pact files without writing a provider verification test. This is the single largest capability gap between the two options; see Bi-Directional Contract Testing Explained for the mechanics.
- Webhooks need to carry credentials (API keys, JWT tokens) for private CI systems. PactFlow stores webhook secrets encrypted; the open-source broker stores them in plaintext in the database.
- Your organization’s security policy requires SSO — the open-source broker has no SAML/OIDC support.
- You have more than five engineers contributing pacts and need separate access tokens per team or read-only tokens for downstream consumers.
- You are already paying for SmartBear tooling (ReadyAPI, SwaggerHub) and PactFlow licensing is bundled or discounted.
Feature Comparison
| Feature | Pact Broker (OSS) | PactFlow Starter | PactFlow Team |
|---|---|---|---|
| Hosting | Self-managed Docker / k8s | Managed SaaS | Managed SaaS |
| Maintenance | You own upgrades and DB | None | None |
| can-i-deploy | Yes | Yes | Yes |
| Webhooks | Yes (no secret storage) | Yes + encrypted secrets | Yes + encrypted secrets |
| Bi-directional contracts | No | Yes | Yes |
| HAL browser / UI | Yes | Yes (enhanced) | Yes (enhanced) |
| Environment tracking | Yes | Yes | Yes |
| SSO (SAML / OIDC) | No | No | Yes |
| Role-based access control | No | No | Yes |
| Audit log | No | No | Yes |
| Support SLA | Community forum | Email support | Priority support |
| Users | Unlimited | Up to 5 | Up to 20 |
| Teams / namespaces | No | 2 | Unlimited |
| Price | Infra cost only | $0 | ~$300/mo (check pactflow.io) |
Self-Hosted Pact Broker: Annotated docker-compose
A production-ready self-hosted broker needs only two containers: Postgres and the broker itself. The configuration below is suitable for a small team running on a VPS, Fly.io, or an internal k8s cluster.
# docker-compose.yml — Pact Broker 2.x + Postgres 15
# Run with: docker compose up -d
version: "3.9"
services:
postgres:
image: postgres:15-alpine
restart: unless-stopped
environment:
POSTGRES_USER: pact # broker DB user
POSTGRES_PASSWORD: "${DB_PASSWORD}" # set in .env or CI secret
POSTGRES_DB: pact
volumes:
- pact_postgres_data:/var/lib/postgresql/data # persist across restarts
healthcheck:
test: ["CMD", "pg_isready", "-U", "pact"]
interval: 10s
retries: 5
broker:
image: pactfoundation/pact-broker:2.x.x # pin a specific release tag
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy # wait for Postgres to accept connections
ports:
- "9292:9292" # expose the broker UI and API
environment:
PACT_BROKER_DATABASE_URL: "postgres://pact:${DB_PASSWORD}@postgres/pact"
PACT_BROKER_BASIC_AUTH_USERNAME: "${BROKER_USER}" # read/write UI login
PACT_BROKER_BASIC_AUTH_PASSWORD: "${BROKER_PASSWORD}"
PACT_BROKER_ALLOW_PUBLIC_READ: "false" # lock down the API
PACT_BROKER_BASE_URL: "https://pact.internal.example.com" # canonical URL for links
PACT_BROKER_LOG_LEVEL: "info"
# Optional: auto-delete pact versions older than 90 days to keep DB lean
PACT_BROKER_DELETE_PACTICIPANT_VERSION_CONTENT_AFTER_DAYS: "90"
volumes:
pact_postgres_data:
Environment file (.env — never commit this):
DB_PASSWORD=a-strong-random-password
BROKER_USER=admin
BROKER_PASSWORD=another-strong-password
Put the broker behind a TLS-terminating reverse proxy (nginx, Caddy, or a cloud load balancer). Point PACT_BROKER_BASE_URL at the public HTTPS address — the broker embeds this in webhook payloads and HAL links, and an HTTP address here causes webhook delivery to insecure endpoints.
Publishing Pacts: Broker vs PactFlow Side-by-Side
The pact-broker publish command is identical for both targets. The only differences are the URL and the token format.
Publishing to the self-hosted broker
# Uses HTTP basic auth via the token format "user:password" encoded in PACT_BROKER_TOKEN,
# or pass --broker-username / --broker-password explicitly.
npx pact-broker publish ./pacts \
--consumer-app-version "$GITHUB_SHA" \
--branch "$GITHUB_REF_NAME" \
--broker-base-url "https://pact.internal.example.com" \
--broker-username "$BROKER_USER" \
--broker-password "$BROKER_PASSWORD"
Publishing to PactFlow
# PactFlow issues a bearer token (PACT_BROKER_TOKEN) from Settings → API Tokens.
# The --broker-token flag sends it as Authorization: Bearer <token>.
npx pact-broker publish ./pacts \
--consumer-app-version "$GITHUB_SHA" \
--branch "$GITHUB_REF_NAME" \
--broker-base-url "https://your-team.pactflow.io" \
--broker-token "$PACT_BROKER_TOKEN"
Migrating from self-hosted to PactFlow
Switching targets is a one-line CI environment variable change: replace PACT_BROKER_BASE_URL and swap --broker-username/--broker-password for --broker-token. No application code changes, no pact file format changes. Historical verification results are not migrated, but all new publish and verify calls start populating the PactFlow matrix immediately.
# GitHub Actions: set these as repository secrets, then use them in every job
# Old:
# PACT_BROKER_URL: https://pact.internal.example.com
# PACT_BROKER_USER: admin
# PACT_BROKER_PASS: ...
# New:
# PACT_BROKER_URL: https://your-team.pactflow.io
# PACT_BROKER_TOKEN: <bearer-token-from-pactflow-settings>
Gating deployments with can-i-deploy (identical syntax on both)
npx pact-broker can-i-deploy \
--pacticipant "user-api" \
--version "$GITHUB_SHA" \
--to-environment production \
--broker-base-url "$PACT_BROKER_URL" \
--broker-token "$PACT_BROKER_TOKEN" \
--retry-while-unknown 12 \
--retry-interval 10
The can-i-deploy command is part of the open-source pact-broker CLI and works against either backend. The broker token flag accepts basic-auth credentials formatted as username:password for the self-hosted broker when you have not configured a bearer token.
Recommendation for Small Teams
For a team of two to ten engineers with fewer than fifteen services, the decision tree is straightforward:
Start with PactFlow Starter (free tier) unless you have a regulatory or budget blocker. The Starter plan covers five users and two team namespaces — enough for most small teams. You get managed infrastructure, encrypted webhook secrets, and the bi-directional contract testing feature from day one. The total cost is zero until you exceed the user limit, at which point you either upgrade to the Team plan or migrate to self-hosted.
Self-host if: your organization prohibits sending contract data to a third-party SaaS, you are already running a container platform that makes the ops overhead negligible, or your team has grown past PactFlow Starter limits and the Team plan’s cost is not justified by the bi-directional feature or SSO requirement.
Do not self-host if: your team lacks anyone comfortable operating a Postgres-backed Docker service in production, you need webhook secrets, or you plan to adopt bi-directional contract testing to validate existing OpenAPI specs against consumer pact files.
The practical sequence for a new team: start on PactFlow Starter, get can-i-deploy gates working across all services, and then decide at the five-user boundary whether to upgrade or migrate. The migration is low risk because the CLI interface is identical.
For the full end-to-end workflow — consumer tests, provider states, and CI integration — see verifying provider contracts in CI with Pact.
Verification
Once your broker is running (self-hosted or PactFlow), validate the connection before wiring up CI:
# Confirm the broker responds and basic auth / token is accepted
curl -u "$BROKER_USER:$BROKER_PASSWORD" https://pact.internal.example.com/diagnostic/status
# Expected: {"status":"ok","version":"2.x.x","branch":"..."}
# For PactFlow with bearer token:
curl -H "Authorization: Bearer $PACT_BROKER_TOKEN" https://your-team.pactflow.io/diagnostic/status
# List all registered pacticipants (empty on a fresh install)
npx pact-broker list-latest-pact-versions \
--broker-base-url "$PACT_BROKER_URL" \
--broker-token "$PACT_BROKER_TOKEN"
A healthy self-hosted broker also serves the HAL browser at / — opening that URL in a browser and seeing the navigation links confirms the application and Postgres connection are working correctly.
After your first publish-and-verify cycle, inspect the matrix:
npx pact-broker can-i-deploy \
--pacticipant "web-frontend" \
--version "$GITHUB_SHA" \
--to-environment production \
--broker-base-url "$PACT_BROKER_URL" \
--broker-token "$PACT_BROKER_TOKEN" \
--output table
The --output table flag prints each participant row and its verification status, making it easy to spot missing verifications in a new setup.
Edge Cases and Caveats
- Database backup is entirely your responsibility on the self-hosted broker. The broker stores the full pact and verification history in Postgres. A lost database means your
can-i-deploymatrix is empty — all gates will block until every provider re-publishes verification results. Schedule dailypg_dumpexports and test restoration periodically. - PactFlow Starter does not support SSO or per-team tokens. If your organization’s security policy requires SSO, you must upgrade to the PactFlow Team plan; there is no SSO option on the open-source broker at all. Do not work around this by sharing a single token across teams — rotate tokens per service using the PactFlow API tokens page or broker basic-auth accounts.
- Webhook secret storage differs materially. The self-hosted broker stores webhook request headers (including
Authorizationvalues) in plaintext in Postgres. Anyone with database access can read CI tokens. If your webhooks call private CI endpoints with credentials, either use PactFlow (which encrypts secrets), use a short-lived token rotated by a secrets manager, or proxy webhook calls through a system that injects credentials at delivery time.
Frequently Asked Questions
Can a small team run the Pact Broker for free indefinitely?
Yes. The open-source Pact Broker is MIT-licensed and free to self-host on any container platform. The only costs are the compute and storage you provision, and the engineer time required to maintain it.
What does PactFlow add that the open-source Pact Broker does not have?
PactFlow adds bi-directional contract testing (provider-side OpenAPI or Postman collection upload), secret management for webhooks, team-scoped access tokens, SSO via SAML/OIDC, role-based access control, and a managed SLA. None of these exist in the open-source broker.
How much does PactFlow cost for a small team?
PactFlow’s Starter plan is free for up to 5 users and 2 teams. The Team plan starts at around $300 per month and supports up to 20 users. Enterprise pricing is negotiated separately. Check pactflow.io for current pricing as it changes.
Does can-i-deploy work with the self-hosted Pact Broker?
Yes. can-i-deploy is a core feature of the open-source broker, not a PactFlow exclusive. Both implementations support the same CLI flags and environment selectors.
Can I migrate from the self-hosted Pact Broker to PactFlow later?
Yes. The wire format is identical. You update PACT_BROKER_URL and PACT_BROKER_TOKEN in your CI environment and existing pact-broker CLI commands work without code changes. Historical contract data is not migrated automatically, but new publishes pick up immediately.
Does PactFlow support bi-directional contract testing for gRPC or GraphQL?
PactFlow’s bi-directional feature currently supports OpenAPI specs and Postman collections as provider-side contracts. gRPC (Protocol Buffers) and GraphQL SDL uploads are not natively supported as of mid-2026; those protocols are handled through Pact’s standard consumer-driven flow.