Configuration
pgfence reads configuration from .pgfence.toml or .pgfence.json in the current working directory. CLI flags override the file when both are present.
Config File
pgfence does not walk ancestor directories looking for config. It reads the config file from the directory you run it in.
# .pgfence.toml
format = "auto"
output = "cli"
min-pg-version = 14
max-risk = "high"
require-lock-timeout = true
require-statement-timeout = true
max-lock-timeout = 5000
max-statement-timeout = 600000
disable-rules = ["rename-column"]
plugins = ["./rules/team-rules.mjs"] The same config can be expressed in JSON:
{
"format": "auto",
"output": "cli",
"min-pg-version": 14,
"max-risk": "high",
"require-lock-timeout": true,
"require-statement-timeout": true,
"max-lock-timeout": 5000,
"max-statement-timeout": 600000,
"disable-rules": ["rename-column"],
"plugins": ["./rules/team-rules.mjs"]
} Options
| Option | Default | Description |
|---|---|---|
format | auto | Migration format: sql, typeorm, prisma, knex, drizzle, sequelize, or auto |
output | cli | Reporter output: cli, json, github, sarif, or gitlab |
db-url | Database URL for size-aware scoring | |
stats-file | Path to a JSON stats snapshot as an alternative to db-url | |
min-pg-version | 14 | Minimum PostgreSQL version to assume for version-sensitive checks |
max-risk | high | Risk threshold for --ci |
require-lock-timeout | true | Require SET lock_timeout in every migration |
require-statement-timeout | true | Require SET statement_timeout in every migration |
max-lock-timeout | Warn when lock_timeout exceeds this many milliseconds | |
max-statement-timeout | Warn when statement_timeout exceeds this many milliseconds | |
disable-rules | Suppress specific rule IDs | |
enable-rules | Whitelist only these rule IDs | |
snapshot | Schema snapshot JSON for definitive type-change analysis | |
plugins | Plugin file paths, resolved from the current working directory |
PostgreSQL Version
pgfence is tested against PostgreSQL 14 through 17. The default minimum is PG 14. Set --min-pg-version or the config-file equivalent to override if needed:
pgfence analyze --min-pg-version 12 migrations/*.sql Version-sensitive behavior:
| Pattern | PG 11+ | PG 12+ | PG 14+ |
|---|---|---|---|
ADD COLUMN ... DEFAULT <constant> | Metadata-only (LOW) | Metadata-only (LOW) | Metadata-only (LOW) |
ALTER TYPE ... ADD VALUE | ACCESS EXCLUSIVE (MEDIUM) | EXCLUSIVE, instant (LOW) | EXCLUSIVE, instant (LOW) |
RENAME COLUMN | ACCESS EXCLUSIVE | ACCESS EXCLUSIVE | Instant (LOW) |
DETACH PARTITION CONCURRENTLY | Not available | Not available | SHARE UPDATE EXCLUSIVE (LOW) |
REINDEX CONCURRENTLY | Not available | Available | Available |
Inline Ignore
Add an inline comment immediately before a statement to suppress checks for it. The directive applies only to the single statement that follows.
Suppress all checks
-- pgfence-ignore
DROP TABLE old_sessions; Use this to explicitly acknowledge a statement that pgfence cannot fully analyze, such as dynamic SQL, or when you have reviewed the risk and accepted it.
Suppress specific rule
-- pgfence-ignore: drop-table
DROP TABLE old_logs;
-- pgfence-ignore: add-column-not-null-no-default
ALTER TABLE audit_log ADD COLUMN meta JSONB NOT NULL DEFAULT '{}'; Suppress multiple rules
-- pgfence-ignore: drop-table, prefer-robust-drop-table
DROP TABLE old_queue; Syntax reference
| Syntax | Effect |
|---|---|
-- pgfence-ignore | Suppress all checks for the next statement |
-- pgfence-ignore: <ruleId> | Suppress one specific rule |
-- pgfence-ignore: <ruleId>, <ruleId> | Suppress multiple rules (comma-separated) |
-- pgfence: ignore <ruleId> | Legacy syntax, still supported |
--output json to see the ruleId for any check you want to suppress.