RLS (Row-Level Security)
Row-Level Security (RLS) is a database security technology that ensures each row is accessible only to the correct user or tenant. In Supabase (and PostgreSQL databases generally), RLS is enforced at the database level — not the application level — which provides an additional layer of security.
Row-Level Security (RLS) is a row-level security mechanism built into PostgreSQL-based databases that determines which rows in a table each user is allowed to see, insert, update, or delete. Instead of relying solely on application logic to filter data by permission, RLS enforces the rule directly inside the database through 'policies' that are defined once and apply to every query, from every source — even if someone accesses the database directly. This is especially critical in multi-tenant architecture, where several organizations share the same database but require complete isolation from one another. The most common mistake is relying only on application-level filtering (adding 'WHERE tenant_id = ...' to every query) — a single human error in one query exposes another tenant's data. In StoreChart, RLS is enforced through Supabase and guarantees complete isolation between tenants at the database level itself — a protective layer that stays effective even if a bug exists in the application code.
A concrete way to see why RLS matters: imagine an application bug that accidentally omits a "WHERE tenant_id = current_tenant" clause from one report query. Without RLS, that single missing line leaks every tenant's data through that one report. With RLS enforced at the database level, the database itself silently rejects or filters out rows the connection isn't authorized to see, regardless of what the application code did or didn't include — turning a critical data-breach bug into a non-event. This is why RLS is considered defense-in-depth: it doesn't replace careful application code, but it means one mistake in one query can't expose the entire dataset.
RLS is best understood as a second, independent layer of enforcement below the application code — even if a developer writes a query that forgets to scope by tenant, the database itself refuses to return rows the current session isn't authorized to see. This defense-in-depth approach is precisely why platforms handling sensitive multi-tenant data (financial records, customer PII, order history) increasingly treat RLS as a baseline requirement rather than an optional hardening step, since application-layer mistakes are common but the database layer rarely lies.
For a business evaluating a SaaS platform to trust with financial or customer data, asking directly whether row-level security is enforced at the database layer, rather than only in application code, is a legitimate and increasingly common due-diligence question worth asking before signing up.
Frequently asked questions
There is a small performance cost since policies are evaluated on every query, but a well-indexed policy (typically filtering on an indexed tenant_id column) adds negligible overhead compared to the security benefit, and modern Postgres query planners optimize RLS policies effectively.
It's a general PostgreSQL feature — Supabase exposes and documents it prominently because it fits naturally with Supabase's direct-database-access model, but any PostgreSQL database can define and enforce RLS policies.
Yes — RLS policies typically don't apply to a database superuser or service-role connection by design, since backend jobs sometimes need cross-tenant access. This makes it critical to keep service-role credentials tightly restricted to trusted backend code only, never exposed to a client.