_ _ _ __ _
__ _ _ __ (_) __| |_ __(_)/ _|| |_
/ _` | '_ \| |/ _` | '__| | |_ | __|
| (_| | |_) | | (_| | | | | _|| |_
\__,_| .__/|_|\__,_|_| |_|_| \__|
|_|
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