10 releases (breaking)
Uses new Rust 2024
| new 0.8.0 | Mar 6, 2026 |
|---|---|
| 0.6.0 | Feb 17, 2026 |
| 0.4.0 | Dec 29, 2025 |
#634 in Command line utilities
2,230 downloads per month
325KB
6.5K
SLoC
Diesel Guard 🐘💨
Linter for dangerous Postgres migration patterns in Diesel and SQLx.

✓ Detects operations that lock tables or cause downtime
✓ Provides safe alternatives for each blocking operation
✓ Works with both Diesel and SQLx migration frameworks
✓ Supports safety-assured blocks for verified operations
✓ Extensible with custom checks
Why diesel-guard?
Uses PostgreSQL's own parser. diesel-guard embeds libpg_query — the C library compiled into Postgres itself. What diesel-guard flags is exactly what Postgres sees. If your SQL has a syntax error, diesel-guard reports that too.
Scriptable custom checks. Write project-specific rules in Rhai with full access to the SQL AST. No forking required.
Version-aware. Configure postgres_version to suppress checks that don't apply
to your version (e.g., constant defaults are safe on PG 11+).
No database connection required. Works on SQL files directly — no running Postgres instance needed in CI.
Quick Start
cargo install diesel-guard
diesel-guard init # creates diesel-guard.toml
diesel-guard check migrations/
When it finds an unsafe migration:
❌ Unsafe migration detected in migrations/20240101_add_admin/up.sql
❌ ADD COLUMN with DEFAULT
Problem:
Adding column 'admin' with DEFAULT on table 'users' requires a full table
rewrite on Postgres < 11, acquiring an ACCESS EXCLUSIVE lock.
Safe alternative:
1. Add the column without a default:
ALTER TABLE users ADD COLUMN admin BOOLEAN;
2. Backfill data in batches (outside migration):
UPDATE users SET admin = false WHERE admin IS NULL;
3. Add default for new rows only:
ALTER TABLE users ALTER COLUMN admin SET DEFAULT false;
CI/CD
Add to your GitHub Actions workflow:
- uses: ayarotsky/diesel-guard-action@v1
What It Detects
24 built-in checks across locking, rewrites, and schema safety:
| Check | Risk |
|---|---|
| ADD COLUMN with DEFAULT | Table rewrite on Postgres < 11 (ACCESS EXCLUSIVE) |
| ADD INDEX without CONCURRENTLY | Blocks writes (SHARE lock) |
| ADD NOT NULL constraint | Full table scan (ACCESS EXCLUSIVE) |
| ADD PRIMARY KEY | Blocks all operations during index creation |
| ADD UNIQUE constraint | ACCESS EXCLUSIVE during index build |
| ALTER COLUMN TYPE | Table rewrite (ACCESS EXCLUSIVE) |
| ADD COLUMN with SERIAL | Table rewrite to populate sequence |
| ADD COLUMN with GENERATED STORED | Table rewrite to compute expressions |
| DROP COLUMN | ACCESS EXCLUSIVE lock |
| DROP INDEX without CONCURRENTLY | ACCESS EXCLUSIVE lock |
| DROP PRIMARY KEY | Breaks FK relationships |
| DROP TABLE | Irreversible, ACCESS EXCLUSIVE |
| DROP DATABASE | Irreversible |
| REINDEX without CONCURRENTLY | ACCESS EXCLUSIVE lock |
| RENAME COLUMN | Breaks running app references immediately |
| RENAME TABLE | Breaks running app references, ACCESS EXCLUSIVE |
| TRUNCATE TABLE | ACCESS EXCLUSIVE, cannot be batched |
| ADD COLUMN with JSON | Breaks DISTINCT/GROUP BY |
| ADD COLUMN with CHAR | Storage waste, comparison bugs |
| ADD COLUMN with TIMESTAMP | DST/timezone hazards |
| PRIMARY KEY with INT/SMALLINT | ID exhaustion risk |
| CREATE EXTENSION | Requires superuser |
| CONSTRAINT without name | Auto-names break future migrations |
| CREATE INDEX with 4+ columns | Ineffective, high storage overhead |
Plus custom checks via Rhai scripting.
Escape Hatch
When you've reviewed an operation and confirmed it's safe, wrap it in a safety-assured block to suppress the check:
-- safety-assured:start
ALTER TABLE users DROP COLUMN legacy_field;
-- safety-assured:end
Further Reading
Credits
Inspired by strong_migrations by Andrew Kane.
License
If this looks useful, a star helps more developers find it ⭐
Dependencies
~21–39MB
~598K SLoC