Drift Scanner
Scanning & drift detection
How snapshots, diffs, and severity work. Understand the difference between INFO, WARNING, and BREAKING changes, and how to accept drift as a new baseline.
Drift Scanner works off two primitives: snapshots and diffs. Everything downstream — alerts, the event history, the dashboard summaries — is derived from these two things.
Baselines
The first snapshot captured for an environment becomes its baseline. The baseline is the "what the schema should look like" reference. Drift Scanner compares every subsequent snapshot against it.
You can re-baseline at any time. Accepting drift (see below) tells Drift Scanner "yes, the current state is the new truth" and promotes the latest snapshot to the baseline.
Scheduled scans
On every tick of the environment's cron schedule, Drift Scanner:
- Connects to the database using the credentials you registered
- Pulls metadata from
pg_catalog - Builds a fresh snapshot and stores it
- Diffs the new snapshot against the baseline
- If the diff is non-empty, creates a drift event and fires alerts
A single scan on a modest database takes a few seconds. The service runs up to 100 concurrent environment scans platform-wide, with a 5-second connection timeout and a bulkhead of 20 concurrent drift scans.
Manual scans
You can trigger an ad-hoc scan from the dashboard or the API (POST /api/v1/drift/environments/{id}/scan). Manual scans are rate-limited per tier:
| Tier | Manual scans / minute |
|---|---|
| Free | 3 |
| Pro | 10 |
| Growth | 30 |
| Scale | 60 |
Diff severity
Every change in a diff is assigned a severity. The event's overall severity is the highest severity of any single change.
INFO — safe additions
Changes that cannot break existing workloads. Examples:
- Adding a new index (non-unique)
- Adding a new nullable column with a default
- Adding a new table
- Adding a new function
WARNING — risky additions
Changes that are additive but can cause runtime pain in the wrong shape. Examples:
- Adding a
NOT NULLcolumn without a default (blocks inserts from older code paths) - Adding a unique index on a column that may already contain duplicates
- Widening a primary key
BREAKING — destructive changes
Changes that remove or rewrite committed schema. Examples:
- Dropping a column, table, index, or constraint
- Changing a column type
- Tightening a nullability constraint (
NULL→NOT NULL) - Removing a foreign key
Each diff item carries severity, table, column, changeType, description, recommendation, and estimatedImpact — so you can surface actionable context in your alerts.
Drift events
When a scan produces a non-empty diff, Drift Scanner writes a DriftEvent with:
id— event UUIDenvId— environment UUIDbaselineId/currentId— the two snapshot IDs being comparedseverity—INFO,WARNING, orBREAKINGbreakingCount,warningCount,infoCountacknowledged— did someone mark this as reviewed?detectedAt— when the scan that produced the event ranitems— the full list ofDiffItems
Events are paginated through GET /api/v1/drift/events.
Acknowledging an event
Call POST /api/v1/drift/events/{id}/acknowledge (or click Acknowledge in the dashboard) to mark an event as reviewed. This does not change the baseline — it just signals that a human has seen it.
Accepting drift (re-baselining)
Acknowledgement and re-baselining are different. Re-baselining promotes the latest snapshot to become the new baseline, so future diffs are measured against it. Use this when:
- You shipped an intentional migration and want to stop getting alerts about it
- You manually hot-fixed the schema in production and have since committed it upstream
Re-baselining is available in the dashboard. It is not yet exposed as its own endpoint — use acknowledge + the next scheduled scan for now if you only care about silencing future alerts on already-seen drift.
Comparing two environments
You can also diff two environments directly (e.g. staging vs. production) via POST /api/v1/drift/compare — useful for "did my staging soak miss something?" audits. See the API reference for the request shape.