Skip to main content
Back to Insights
Engineering7 min read24 March 2026

Multi-tenant architecture and row-level security in compliance software

Compliance software serving regulated industries must solve a fundamental architectural problem: multiple organisations need to use the same platform, but their data must be completely isolated from each other. A law firm's suspicious matter reports cannot be visible to another law firm on the same platform. An NDIS provider's participant records cannot bleed into another provider's instance. This requirement — multi-tenancy with strict data isolation — is not primarily a UI problem or a business logic problem; it is a database architecture problem, and the solution that provides the strongest guarantees is row-level security enforced at the database layer.

Row-level security (RLS) is a PostgreSQL feature that allows access policies to be defined at the table level, enforced by the database engine itself, regardless of which application layer is making the query. A correctly configured RLS policy means that even if an application bug, a misconfigured API route, or a compromised session token causes a query to execute without expected filtering, the database will not return rows belonging to a different tenant. The enforcement is at the lowest level of the stack — below the application, below the API, below the ORM. This architectural property is what separates genuine data isolation from data isolation that depends on every developer never making a mistake.

Implementing RLS in a multi-tenant system requires a consistent approach to how tenant identity is threaded through the stack. In Supabase, this typically involves setting a session variable — such as app.current_tenant_id — at the start of each database session, and writing RLS policies that compare the tenant_id column on each table against that variable. The result is that every SELECT, INSERT, UPDATE, and DELETE operation is automatically scoped to the current tenant. Developers writing application code do not need to remember to add WHERE tenant_id = ? clauses — the database enforces it. This dramatically reduces the surface area for data isolation bugs.

The architectural trade-off in multi-tenant systems is between isolation and operational complexity. Fully separate databases per tenant provide maximum isolation but require per-tenant infrastructure provisioning, separate backup and recovery processes, and significant operational overhead at scale. Shared database with shared schema and RLS provides strong isolation with much lower operational complexity — one database, one backup process, one migration pipeline. For compliance software serving tens or hundreds of regulated entities, shared schema with RLS is the operationally practical choice, provided the RLS policies are implemented correctly and reviewed as part of every schema change.

The compliance implications of getting this wrong are severe. A data isolation breach — where one tenant's data becomes visible to another — in a compliance software context is not merely a technical incident. It may constitute a disclosure of suspicious matter reports in violation of the AML/CTF Act's tipping-off provisions, a breach of the Privacy Act's confidentiality obligations, or a notifiable data breach requiring mandatory reporting to the Office of the Australian Information Commissioner. Regulators do not accept 'software bug' as a complete explanation. They want to understand why the architecture did not prevent the breach, and the answer 'we relied on application-layer filtering' will not satisfy them. RLS is not over-engineering; for compliance software, it is the minimum defensible standard.

Need help with compliance software?

We build production software for regulated Australian industries.

Get in touch