pgrls vs. Atlas — do I need both?
Short answer: yes, if you’re using Atlas to manage RLS. Atlas writes and applies your policies as code. pgrls audits what those policies do once applied. The roles are different layers of the same workflow.
The kind of bug each one catches
Atlas (github.com/ariga/atlas) fires on migration / schema hazards like this:
-- Atlas refuses to migrate this without manual ack:
DROP COLUMN owner_id; -- destructive, possibly data-losing
It has 50+ analyzers covering destructive changes, lock-held operations, drift detection — the migration-safety layer.
pgrls fires on a different class of bug. Even if Atlas applies your policy cleanly, this still ships:
CREATE POLICY admins_only ON public.documents
FOR ALL TO authenticated
USING (auth.jwt() -> 'user_metadata' ->> 'role' = 'admin');
user_metadata is end-user writable via Supabase’s auth API (supabase.auth.updateUser({ data: { role: 'admin' }})). Atlas applied a policy that’s syntactically valid but semantically self-bypassable. pgrls flags it as SEC033.
Capability check
| Atlas | pgrls | |
|---|---|---|
| Manages schema as code | ✓ | — |
| Generates migrations | ✓ | — |
| 50+ DDL safety analyzers | ✓ | — |
| Catches RLS bypass / semantic bugs | — | ✓ (46 rules) |
| Auto-fix RLS findings | — | ✓ (12 of 46) |
| Multi-database | ✓ (PG/MySQL/MSSQL/…) | — (Postgres only) |
Wire them together
The natural pipeline:
1. Atlas — writes RLS policies as declarative code, generates the migration.
2. CI applies the migration.
3. pgrls — reads the resulting catalog, audits the policies' semantics.
4. pgrls fix output (for 12 rule classes) → next Atlas migration.
Atlas guarantees the policy is applied as written. pgrls verifies that what was written is actually correct.
Verdict
Use both. Atlas asks “is the schema in the database what we declared?” pgrls asks “does the declared schema actually enforce what we meant?” No overlap on findings; full coverage when stacked.