Staywally™
All writing
Engineering8 Aug 2026 · 9 min read

Row-level security, and why we let the database say no

Every tenant query goes through Postgres RLS rather than an application check. Here is what that bought us.

JMJoseph MathewCo-founder, CTO

Multi-tenancy bugs are the kind that end a company. We decided early that no amount of code review would make us confident in a `WHERE tenant_id = ?` written by hand in four hundred places.

The rule

Every tenant-scoped table has a row-level security policy keyed on a session variable. The application sets that variable once, when it opens the connection, from the authenticated session. After that, a query that forgets its tenant filter returns nothing rather than everything.

What it cost

  • Connection pooling had to become tenant-aware, which took a week.
  • Some analytical queries across tenants need an explicitly elevated role, used in exactly three places.
  • Migrations are noisier: every new table needs its policy in the same commit, enforced by a test.

What it bought

In three years we have had no cross-tenant data exposure. We have had several bugs that would have caused one, and every single time the database returned an empty result and someone filed a confusing ticket instead of a breach report. That trade has been worth every hour.