MG Software.
HomeAboutServicesPortfolioBlogCalculator
Contact Us
MG Software
MG Software
MG Software.

MG Software builds custom software, websites and AI solutions that help businesses grow.

© 2026 MG Software B.V. All rights reserved.

NavigationServicesPortfolioAbout UsContactBlogCalculator
ServicesCustom developmentSoftware integrationsSoftware redevelopmentApp developmentSEO & discoverability
Knowledge BaseKnowledge BaseComparisonsExamplesAlternativesTemplatesToolsSolutionsAPI integrations
LocationsHaarlemAmsterdamThe HagueEindhovenBredaAmersfoortAll locations
IndustriesLegalEnergyHealthcareE-commerceLogisticsAll industries
MG Software.
HomeAboutServicesPortfolioBlogCalculator
Contact Us
MG Software
MG Software
MG Software.

MG Software builds custom software, websites and AI solutions that help businesses grow.

© 2026 MG Software B.V. All rights reserved.

NavigationServicesPortfolioAbout UsContactBlogCalculator
ServicesCustom developmentSoftware integrationsSoftware redevelopmentApp developmentSEO & discoverability
Knowledge BaseKnowledge BaseComparisonsExamplesAlternativesTemplatesToolsSolutionsAPI integrations
LocationsHaarlemAmsterdamThe HagueEindhovenBredaAmersfoortAll locations
IndustriesLegalEnergyHealthcareE-commerceLogisticsAll industries
MG Software.
HomeAboutServicesPortfolioBlogCalculator
Contact Us
MG Software
MG Software
MG Software.

MG Software builds custom software, websites and AI solutions that help businesses grow.

© 2026 MG Software B.V. All rights reserved.

NavigationServicesPortfolioAbout UsContactBlogCalculator
ServicesCustom developmentSoftware integrationsSoftware redevelopmentApp developmentSEO & discoverability
Knowledge BaseKnowledge BaseComparisonsExamplesAlternativesTemplatesToolsSolutionsAPI integrations
LocationsHaarlemAmsterdamThe HagueEindhovenBredaAmersfoortAll locations
IndustriesLegalEnergyHealthcareE-commerceLogisticsAll industries
MG Software.
HomeAboutServicesPortfolioBlogCalculator
Contact Us
  1. Home
  2. /Knowledge Base
  3. /What is Row-Level Security (RLS)? Data Isolation in PostgreSQL for SaaS

What is Row-Level Security (RLS)? Data Isolation in PostgreSQL for SaaS

Row-level security filters database rows by user permissions directly in PostgreSQL. From multi-tenant isolation and RBAC integration to Supabase policies: learn how RLS enforces data security at the database level.

Row-Level Security (RLS) is a built-in database feature in PostgreSQL that controls at the row level which data a user can read, create, update, or delete. Through declarative policies, access rules are defined per table that are automatically and transparently enforced on every query, regardless of the source of the request. RLS operates at the database level, fully independent of application code, making it a fundamental defense layer for data isolation in multi-tenant SaaS applications and compliance with privacy regulations like GDPR.

What is Row-Level Security? - Definition & Meaning

What is Row?

Row-Level Security (RLS) is a built-in database feature in PostgreSQL that controls at the row level which data a user can read, create, update, or delete. Through declarative policies, access rules are defined per table that are automatically and transparently enforced on every query, regardless of the source of the request. RLS operates at the database level, fully independent of application code, making it a fundamental defense layer for data isolation in multi-tenant SaaS applications and compliance with privacy regulations like GDPR.

How does Row work technically?

RLS in PostgreSQL is activated per table with ALTER TABLE tablename ENABLE ROW LEVEL SECURITY. Once enabled, the default policy is deny-all: no rows are visible unless an explicit policy grants access. Policies are created with CREATE POLICY and can be scoped to specific operations: FOR SELECT, FOR INSERT, FOR UPDATE, and FOR DELETE. A typical multi-tenant policy filters on tenant_id: CREATE POLICY tenant_isolation ON orders USING (tenant_id = current_setting('app.tenant_id')::uuid). The USING clause filters which existing rows are visible, while WITH CHECK validates which rows may be inserted or modified. The user context is typically set via SET LOCAL or set_config() at the beginning of each request. In Supabase, the tenant_id is automatically derived from the JWT token of the authenticated user. The auth.uid() function returns the user ID and auth.jwt() provides access to custom claims in the token. RLS integrates seamlessly with Role-Based Access Control (RBAC). Policies can combine conditions: an admin role sees all rows, a user role sees only their own data, and a viewer role sees all organization data but cannot modify anything. This is implemented through OR conditions or multiple policies per table. For performance, it is crucial that the columns referenced in RLS policies are indexed. A policy on tenant_id without an index on that column results in a full table scan on every query. PostgreSQL applies RLS filters as additional WHERE conditions that are optimized by the query planner together with the original query. The BYPASSRLS privilege allows specific database roles to circumvent RLS, which is necessary for administrative tasks like migrations, data exports, and background processes. In Supabase, this is the service_role key that must only be used server-side. For complex authorization scenarios, policies can leverage subqueries and functions. A policy can verify whether a user is a member of a specific team through a subquery on the team_members table. Security definer functions encapsulate complex authorization logic that is reused across multiple policies. This prevents duplication and makes the authorization model centrally manageable from a limited number of functions.

How does MG Software apply Row in practice?

MG Software implements RLS in every multi-tenant SaaS application we build on Supabase. Our standard approach begins with enabling RLS on all tables containing tenant data, combined with a default-deny policy that prevents new tables from being accidentally unprotected after a migration. Policies are based on the tenant_id stored as a custom claim in the Supabase JWT token. Upon authentication, the tenant context becomes automatically available via auth.jwt()->'tenant_id'. This eliminates the need to implement tenant filtering in application code and guarantees isolation regardless of how the data is accessed. For administrative tasks and background processes, we use the Supabase service_role key that bypasses RLS. This key is used exclusively server-side in protected API routes and background processes, never in client-side code. For every new table, we document the expected RLS policies in the migration script and test them with automated tests that execute queries from different user contexts to detect cross-tenant leaks.

Why does Row matter?

Row-Level Security provides a defense layer for data isolation that functions independently of application code. In multi-tenant SaaS, RLS prevents bugs, API errors, or incorrect queries from accidentally exposing data belonging to other tenants. This is not merely a best practice but a requirement for compliance with regulations like GDPR. During security audits, RLS serves as concrete evidence that data isolation is implemented at the infrastructure level. Without RLS, data isolation depends entirely on correct WHERE clauses in every application query. A single forgotten filter in a new endpoint or an error in an ORM query can lead to a data breach affecting all tenants. RLS shifts this responsibility to the database itself, where it is enforced consistently and automatically regardless of how data is queried, whether through the application, an admin tool, or a direct database connection.

Common mistakes with Row

Teams often forget to test RLS policies with different user contexts, leaving permission leaks undetected until a security audit or incident. Write automated tests that execute queries as users from different tenants and systematically validate that cross-tenant data is invisible for both read and write operations. A second common mistake is not setting a default-deny policy when enabling RLS. Without an explicit default-deny, new tables without policies are accessible to all authenticated users. Always establish restrictive policies as the baseline and grant access only through explicit GRANT statements. Additionally, performance implications are underestimated: policies on unindexed columns cause full table scans that progressively slow the database as tables grow in size. Always add an index on the column being filtered in the RLS policy.

What are some examples of Row?

  • A multi-tenant SaaS application where the orders table has an RLS policy filtering on tenant_id. The policy uses auth.jwt()->'tenant_id' to identify the current tenant. Users from Organization A see exclusively their own orders, even if the API accidentally omits a tenant filter.
  • A project management tool where team members only see projects they have been invited to. The RLS policy combines tenant isolation with project-level access: USING (tenant_id = auth.jwt()->'tenant_id' AND id IN (SELECT project_id FROM project_members WHERE user_id = auth.uid())).
  • An admin dashboard that uses the service_role key to bypass RLS for cross-tenant reporting and user management. The service_role is invoked exclusively from a server-side API route that enforces its own authentication and authorization.
  • A document-sharing feature where an RLS policy supports multiple access levels: owners can read and write, team members can read, and publicly shared documents are visible to all authenticated users within the same tenant.
  • Automated RLS tests in the CI/CD pipeline that verify for each table that a user from Tenant A cannot read, create, or modify data from Tenant B. The tests use Supabase client libraries with tokens from different test users.

Related terms

single sign onpostgresqlcybersecurity

Further reading

Knowledge BaseWhat Is GDPR? How the EU Privacy Regulation Affects Your Software and BusinessOAuth 2.0 Explained: Authorization, Tokens, Scopes, and Secure Login Without PasswordsSecurity Scanners That Catch Vulnerabilities Before ProductionSecurity Audit Template - Free Download & Example

Related articles

What Is GDPR? How the EU Privacy Regulation Affects Your Software and Business

GDPR mandates how organizations collect, process, and protect personal data of EU citizens. With fines up to 4% of global revenue, understanding privacy by design, data processing agreements, and technical compliance measures is essential.

OAuth 2.0 Explained: Authorization, Tokens, Scopes, and Secure Login Without Passwords

OAuth 2.0 enables secure access to third-party APIs and applications without sharing passwords. Discover how the authorization protocol behind every "Sign in with Google" flow works, which grant types exist, and how to implement it securely.

What is SSL/TLS? - Definition & Meaning

SSL/TLS encrypts the connection between browser and server via HTTPS, which is essential for data protection, user trust, and search engine rankings.

Financial sector software: fintech platforms, compliance automation, secure portals and legacy modernisation

Regulatory complexity should accelerate innovation, not slow it down. We build financial software with PSD2, MiFID II and DORA compliance embedded from day one, enabling faster onboarding, automated risk workflows and real-time reporting that satisfies both customers and regulators.

From our blog

OpenAI Codex Security: AI-Powered Vulnerability Scanning That Found 11,000 Critical Bugs in Beta

Sidney · 7 min read

How AI Tools Created New Security Attack Surfaces: From Vercel to Claude Code

Sidney · 13 min read

Securing Your Business Software: The Essentials

Sidney · 8 min read

Frequently asked questions

PostgreSQL offers the most mature and flexible RLS implementation with CREATE POLICY, USING, and WITH CHECK clauses. SQL Server supports RLS through security predicates with a similar model. Oracle provides Virtual Private Database (VPD) as an equivalent feature. MySQL does not have built-in RLS functionality, requiring data isolation to be implemented entirely in the application layer.
Write automated tests that execute queries as users with different roles and tenant contexts. Verify that a user from Tenant A cannot read, create, update, or delete data from Tenant B. Test edge cases: what happens when a tenant_id is NULL? Use Supabase client libraries with different JWT tokens per test user. Integrate these tests into your CI/CD pipeline so they run on every deployment.
RLS and application-level checks are complementary, not alternatives. RLS provides defense-in-depth at the database level that protects data regardless of how queries are executed. Application-level checks are needed for business logic, UI feedback, and fine-grained authorization that does not fit in a database policy. The best approach combines both: RLS as a safety net and application logic for the user experience.
Supabase makes RLS configuration accessible through a visual editor in the dashboard and via SQL. On each request, the JWT token of the authenticated user is automatically available via auth.uid() and auth.jwt(). Policies can filter on user_id, tenant_id as a custom claim, or roles from the token. The service_role key bypasses RLS for administrative tasks and must only be used server-side.
RLS adds additional WHERE conditions to every query, which are optimized by the PostgreSQL query planner together with the original query. With an index on the column in the RLS policy, typically tenant_id, the impact is minimal. Without an index, a full table scan occurs on every query. Monitor query plans with EXPLAIN ANALYZE after enabling RLS to verify that indexes are being used correctly.
Define multiple policies per table that serve different roles. An admin policy grants access to all rows within the tenant. A user policy restricts access to own data only. A viewer policy allows only SELECT operations. PostgreSQL evaluates all policies with OR logic: if any policy grants access, the row is visible. Use policy names and comments to maintain clarity with complex configurations.
USING filters which existing rows are visible for SELECT, UPDATE, and DELETE queries. WITH CHECK validates which values may be inserted on INSERT or modified on UPDATE. A policy can combine both clauses: USING determines that you only see your own rows, while WITH CHECK prevents creating a row with a tenant_id that does not belong to you. Without WITH CHECK, the USING clause is used as a fallback.

We work with this daily

The same expertise you're reading about, we put to work for clients.

Discover what we can do

Related articles

What Is GDPR? How the EU Privacy Regulation Affects Your Software and Business

GDPR mandates how organizations collect, process, and protect personal data of EU citizens. With fines up to 4% of global revenue, understanding privacy by design, data processing agreements, and technical compliance measures is essential.

OAuth 2.0 Explained: Authorization, Tokens, Scopes, and Secure Login Without Passwords

OAuth 2.0 enables secure access to third-party APIs and applications without sharing passwords. Discover how the authorization protocol behind every "Sign in with Google" flow works, which grant types exist, and how to implement it securely.

What is SSL/TLS? - Definition & Meaning

SSL/TLS encrypts the connection between browser and server via HTTPS, which is essential for data protection, user trust, and search engine rankings.

Financial sector software: fintech platforms, compliance automation, secure portals and legacy modernisation

Regulatory complexity should accelerate innovation, not slow it down. We build financial software with PSD2, MiFID II and DORA compliance embedded from day one, enabling faster onboarding, automated risk workflows and real-time reporting that satisfies both customers and regulators.

From our blog

OpenAI Codex Security: AI-Powered Vulnerability Scanning That Found 11,000 Critical Bugs in Beta

Sidney · 7 min read

How AI Tools Created New Security Attack Surfaces: From Vercel to Claude Code

Sidney · 13 min read

Securing Your Business Software: The Essentials

Sidney · 8 min read

MG Software
MG Software
MG Software.

MG Software builds custom software, websites and AI solutions that help businesses grow.

© 2026 MG Software B.V. All rights reserved.

NavigationServicesPortfolioAbout UsContactBlogCalculator
ServicesCustom developmentSoftware integrationsSoftware redevelopmentApp developmentSEO & discoverability
Knowledge BaseKnowledge BaseComparisonsExamplesAlternativesTemplatesToolsSolutionsAPI integrations
LocationsHaarlemAmsterdamThe HagueEindhovenBredaAmersfoortAll locations
IndustriesLegalEnergyHealthcareE-commerceLogisticsAll industries