Trace Mode
Run your migrations against a disposable Docker Postgres container and compare pgfence's lock predictions with actual PostgreSQL behavior. No credentials needed, no risk to real data.
Quick Start
pgfence trace migrations/*.sql This spins up a temporary postgres:17-alpine container, executes each statement, queries pg_locks and the system catalog after every step, then tears down the container. The entire process is automatic.
What Trace Does
For each statement in your migration, trace mode:
- Executes the statement against a real PostgreSQL instance
- Samples
pg_locksduring execution to observe the lock mode acquired - Diffs system catalog snapshots (
pg_class,pg_constraint,pg_index) to detect table rewrites, implicit index creation, and constraint validation state - Compares actual behavior against pgfence's static analysis predictions
- Reports a verification status for each check
Verification Statuses
| Status | Meaning |
|---|---|
| Confirmed | Static prediction matches actual PostgreSQL behavior |
| Mismatch | Static prediction was wrong; trace result takes precedence |
| Trace-only | Trace found something static analysis missed (e.g., table rewrite, implicit index) |
| Static-only | Policy or best-practice check that trace cannot verify (e.g., missing lock_timeout) |
| Error | Statement failed to execute (syntax error, missing dependency, etc.) |
Options
| Flag | Default | Description |
|---|---|---|
--pg-version <version> | 17 | PostgreSQL version for the Docker container |
--docker-image <image> | postgres:<version>-alpine | Custom Docker image (overrides --pg-version) |
--format <format> | auto | Migration format: sql, typeorm, prisma, knex, drizzle, sequelize, auto |
--output <format> | cli | Output format: cli, json, github, sarif, gitlab |
--ci | false | CI mode: exit 1 on mismatches, errors, or risk threshold violations |
--max-risk <level> | high | Maximum allowed risk level |
--snapshot <path> | Schema snapshot for definitive type analysis | |
--plugin <paths...> | Plugin file paths for custom rules |
pgfence trace uses the same reporter set as pgfence analyze, including GitHub, SARIF, and GitLab output.
Targeting a Specific PostgreSQL Version
bash # Test against PG 14 to match production
pgfence trace --pg-version 14 migrations/*.sql
# Test against PG 15
pgfence trace --pg-version 15 migrations/*.sql
Custom Docker Images
Use --docker-image for extensions like PostGIS, pgvector, or TimescaleDB:
bash # PostGIS
pgfence trace --docker-image postgis/postgis:17 migrations/*.sql
# pgvector
pgfence trace --docker-image pgvector/pgvector:pg17 migrations/*.sql
CI Mode
In CI mode, pgfence trace exits with code 1 when:
- Any finding exceeds the
--max-risk threshold - Any mismatch is detected between static and trace results
- Any statement fails to execute
yaml - name: Verify migration safety
run: pgfence trace --ci --max-risk medium migrations/*.sql
How CONCURRENTLY Statements Are Handled
CREATE INDEX CONCURRENTLY and similar statements cannot run inside a transaction. pgfence handles this by using an observer connection that polls pg_locks during execution to observe the locks it sees. Because the observer is polling, very short-lived lock spikes can still be missed. This is a capability other tools skip entirely.
Session Isolation
Between file traces, pgfence issues RESET ALL to prevent session state leakage. Timeouts, search_path, or other settings set by one migration file do not affect subsequent files.
Security
- Container binds to
127.0.0.1 only (not exposed to the network) - Container password is ephemeral (random 20-char base64url, never written to disk)
- Container is automatically cleaned up on exit, even on errors
- Database credentials are never included in error messages or output
Requirements
Trace mode requires Docker to be installed and running. Use pgfence analyze for static-only analysis without Docker.
Trace with ORM Migrations
Trace mode works with all supported ORM formats:
bash # TypeORM
pgfence trace --format typeorm src/migrations/*.ts
# Knex
pgfence trace --format knex migrations/*.ts
# Auto-detect
pgfence trace migrations/*