Row-Level Security Is Not a Suggestion
Why multi-tenant isolation must happen at the database, not the application.
Here's a thought experiment. You use a SaaS platform. Your competitor also uses the same platform. You both store inventory, grading results, pricing, and client information. The question: what prevents your competitor from seeing your data?
If the answer is "the application code checks which tenant you are and only shows your data" — congratulations, you have application-level security. This means a bug in the application code, a misconfigured API endpoint, a SQL injection, or an overly helpful developer with database access could potentially expose tenant A's data to tenant B.
If the answer is "the database itself enforces isolation, and no query can return data from another tenant regardless of how it's written" — you have row-level security. These are very different things.
The Application Layer Problem
Application-level tenant isolation works like this: every query includes a filter. WHERE tenant_id = 'your-tenant'. The application adds this filter to every database call. If the filter is present, you see your data. If it's absent — because of a bug, an oversight, a new endpoint that forgot the check, or a developer running a quick query in production — the database happily returns everything.
The database doesn't know about tenants. The database just stores rows. It's the application's job to ask for the right ones. And the application, being software written by humans, is capable of making mistakes.
This is not theoretical. Multi-tenant data leaks are one of the most common security incidents in SaaS platforms. A developer writes a new API endpoint and forgets the tenant filter. A migration script runs without the WHERE clause. A debugging session connects directly to the database and runs a SELECT * that returns every tenant's records. Each of these is a simple mistake. Each could expose your inventory, your pricing, your client data.
Application-level security means the lock is on the door. Row-level security means the walls are made of concrete. Doors can be left open. Concrete cannot.
Row-Level Security: The Database as Enforcer
Postgres Row Level Security (RLS) works differently. Instead of relying on the application to filter data, the database itself enforces the rules. Every table has a policy that says: "this tenant can only see rows where tenant_id matches their session." The policy is enforced at the database level. No application code can override it. No query can circumvent it. A SELECT * returns only your rows, not because the application filtered them, but because the database refuses to show you anything else.
If a developer writes a buggy endpoint that forgets the tenant filter, the database still returns only the correct tenant's data. If someone runs a raw query, the policy applies. If a new feature is added in a rush and the access control is incomplete, the database doesn't care — the policy is there, permanent and unforgettable.
RLS doesn't replace application security. You still need authentication, authorisation, and proper API design. But RLS is the safety net — the guarantee that even when the application makes a mistake, tenant data doesn't leak. It's the difference between "we trust the code" and "the architecture won't allow it."
Why It Matters for ITAD
ITAD platforms handle sensitive data by nature. Inventory includes device serial numbers and asset histories. Pricing reveals commercial strategy. Client lists are competitive intelligence. Erasure records contain data about what was on the device before it was wiped — and while the data itself is gone, the metadata (which clients had which devices with which data classifications) is valuable and sensitive.
If you're an ITAD company evaluating a multi-tenant platform, the question "how is my data isolated from other tenants?" should be in your first email. And the answer should be "at the database level, using RLS policies on every table." Not "our application code handles it." Not "we have access controls." Not "our developers are very careful." Careful is not a security architecture. Careful is a hope.
Row-level security is not a feature to be toggled on or off based on preference. It's a foundational architectural decision that determines whether your multi-tenant platform has real isolation or simulated isolation. The difference is invisible when everything works correctly. The difference is everything when something goes wrong.
Your competitor uses the same platform. Can they see your data? If the answer depends on the application never making a mistake, the answer is "not yet."
Like what you read?
Founding members get every article first, plus 12 months free access to the platform.
Get Early Access