_ _ _ __ _
__ _ _ __ (_) __| |_ __(_)/ _|| |_
/ _` | '_ \| |/ _` | '__| | |_ | __|
| (_| | |_) | | (_| | | | | _|| |_
\__,_| .__/|_|\__,_|_| |_|_| \__|
|_|
Catch API schema drift before your users do.
Contributions are welcome.
Please read CONTRIBUTING.md before opening issues or pull requests.
If you find this project useful, please ⭐ star the repo — it helps a lot.
Your API changed. Nobody noticed. A field was renamed. A type flipped from string to number. A key got removed. Your mobile app crashes. Your integrations break. And you find out at 3am.
[3:14 AM] PagerDuty: checkout is broken in prod
[3:19 AM] Root cause: userId changed string → number in last deploy
[3:21 AM] No test caught it. No alert fired. It was live for 6 hours.
apidrift catches this before it reaches production.
apidrift snapshots the shape of your live API responses — not the data, just the structure — and diffs them across versions, environments, or deploys.
# One line. No config. No setup.
apidrift diff https://staging.api.com/users/1 https://prod.api.com/users/1apidrift diff: staging → prod
✗ GET /users/:id
┌──────────┬────────────┬──────────┬──────────┐
│ Field │ Change │ From │ To │
├──────────┼────────────┼──────────┼──────────┤
│ userId │ ● breaking │ "string" │ "number" │
├──────────┼────────────┼──────────┼──────────┤
│ discount │ ● breaking │ "string" │(removed) │
└──────────┴────────────┴──────────┴──────────┘
Summary: 2 breaking, 0 additive
✗ Breaking changes detected
npm install -g apidrift-cliWorks with any project, any API, any language. No config required to get started.
Diff two live URLs instantly. No snapshots, no config.
apidrift diff https://staging.api.com/orders https://prod.api.com/ordersOr diff two saved snapshots by tag:
apidrift diff v1.2 v1.3Force-compare even if the endpoints differ:
apidrift diff https://api.com/users/1 https://api.com/posts/1 --forcecd your-project/
apidrift initWalks you through setup interactively and creates apidrift.config.json:
{
"environments": {
"staging": {
"baseUrl": "https://staging.yourapi.com",
"headers": { "Authorization": "Bearer ${STAGING_TOKEN}" }
},
"prod": {
"baseUrl": "https://api.yourapi.com",
"headers": { "Authorization": "Bearer ${PROD_TOKEN}" }
}
},
"discovery": {
"openapi": "https://api.yourapi.com/openapi.json"
},
"endpoints": []
}After init, create a .env file (or set env vars) so ${STAGING_TOKEN} / ${PROD_TOKEN} resolve:
STAGING_TOKEN=your_token_here
PROD_TOKEN=your_token_here- Add
.envto.gitignore. - If your
Authorizationheader resolves empty (e.g. token missing), apidrift prints a warning before making requests.
Snapshot all your configured endpoints for an environment:
apidrift snapshot --tag v1.0 --env stagingOr snapshot a single URL directly:
apidrift snapshot https://api.yourapi.com/users/1 --tag prod-usersSnapshot only specific methods:
apidrift snapshot --tag v1.0 --env staging --methods GET,POSTAdd a delay between requests (polite to APIs):
apidrift snapshot --tag v1.0 --env staging --delay 200Preview what would be snapshotted without making requests:
apidrift snapshot --tag v1.0 --env staging --dry-runHit two environments right now and diff them on the fly:
apidrift check --envA staging --envB prodCheck specific methods only:
apidrift check --envA staging --envB prod --methods GET,POSTAdd a delay between checks:
apidrift check --envA staging --envB prod --delay 300With dry-run to preview which endpoints would be checked:
apidrift check --envA staging --envB prod --dry-runapidrift listSaved snapshots:
→ v1.0
→ v1.1
→ prod-users
Feed real traffic into apidrift from a HAR file:
apidrift record --har traffic.har --tag nightlyOr pipe it from stdin:
cat traffic.json | apidrift record --stdin --tag ci-run-42# 1. Set up once
apidrift init
# 2. Snapshot before deploy
apidrift snapshot --tag v1.2 --env staging
# 3. Deploy your changes
# 4. Snapshot after deploy
apidrift snapshot --tag v1.3 --env staging
# 5. See exactly what changed
apidrift diff v1.2 v1.3apidrift exits with code 1 on breaking changes — a native CI gate.
# .github/workflows/api-check.yml
name: API Contract Check
on: [push]
jobs:
drift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm install -g apidrift-cli
- run: apidrift check --envA staging --envB prod
env:
STAGING_TOKEN: ${{ secrets.STAGING_TOKEN }}
PROD_TOKEN: ${{ secrets.PROD_TOKEN }}Breaking change detected → pipeline fails → deploy blocked. Zero extra config.
Your Live API What apidrift stores
──────────────── ────────────────────
{ {
userId: 123, ──► userId: "number",
name: "John", name: "string",
tags: ["admin"] tags: ["string"]
} }
snapshot A snapshot B
│ │
└──────────┬───────────────────┘
▼
differ engine
│
┌──────────┴──────────┐
│ breaking │ additive
│ type changed │ new field
│ field removed │ (non-breaking)
└─────────────────────┘
apidrift never stores your actual data — only the shape (field names + types). Safe to use with production APIs.
| Change | What It Means | Severity |
|---|---|---|
| Field removed | A field consumers depend on is gone | 🔴 Breaking |
| Type changed | string → number silently breaks clients |
🔴 Breaking |
| Field added | New undocumented field appeared | 🟡 Additive |
| No change | Schemas match exactly | 🟢 Clean |
- Sensitive fields (
token,password,secret,api_key, etc.) are automatically redacted before schema inference - JWT tokens and credit card patterns in values are also redacted
- Nothing sensitive is ever written to disk
Snapshots are stored globally at ~/.apidrift/snapshots/ — accessible from any project on your machine.
Create a starter apidrift.config.json in current directory.
apidrift init [options]
Options:
-h, --help display help for command
Snapshot all endpoints for an environment or a single URL.
apidrift snapshot [options] [url]
Arguments:
url The URL to snapshot
Options:
--tag <tag> Version tag e.g. v1.0
--env <env> Environment name e.g. staging
--methods <methods> Comma-separated HTTP methods to allow during
discovery/fetch (default: GET)
--dry-run Print endpoints that would be called (no requests)
--delay <ms> Delay in ms between endpoint requests (default: "0")
-h, --help display help for command
Diff two snapshots by tag or two URLs.
apidrift diff [options] <from> <to>
Arguments:
from Base snapshot tag or URL
to Target snapshot tag or URL
Options:
--force Force comparison of different endpoints
-h, --help display help for command
Live diff two environments right now.
apidrift check [options]
Options:
--envA <envA> First environment
--envB <envB> Second environment
--methods <methods> Comma-separated HTTP methods to allow during
discovery/fetch (default: GET)
--dry-run Print endpoints that would be called (no requests)
--delay <ms> Delay in ms between endpoint checks (default: "0")
-h, --help display help for command
List all saved snapshots.
apidrift list [options]
Options:
-h, --help display help for command
Create a snapshot from recorded traffic (stdin or HAR).
apidrift record [options]
Options:
--tag <tag> Version tag e.g. nightly
--stdin Read input from stdin (supports HAR JSON or JSON lines)
--har <file> Read a HAR file from disk
-h, --help display help for command
| Layer | Package |
|---|---|
| CLI | commander |
| HTTP | axios |
| Terminal UI | chalk + cli-table3 + ora |
| Schema engine | custom (zero dependencies) |
| Diff engine | custom recursive differ |
MIT License — see LICENSE. Built by Tanmay Joddar