By Sagar Shankaran, Founder of CallSphere
Move tenant filtering out of your app and into Postgres. Row Level Security gives you database-enforced isolation that survives ORM bugs, hand-rolled SQL, and AI agents writing queries on the fly.
Key takeaways
TL;DR — When AI agents start writing SQL on behalf of users, app-layer tenant filtering becomes a liability. RLS pushes the
tenant_idcheck into the database where no agent can route around it. Set up correctly, it adds <5% query overhead.
A multi-tenant schema where every AI agent query — direct, ORM-generated, or LLM-emitted — is automatically scoped to the calling tenant via session-level GUC variables and RLS policies.
CREATE TABLE conversations (
id BIGSERIAL PRIMARY KEY,
tenant_id UUID NOT NULL,
agent_id UUID NOT NULL,
transcript TEXT,
created_at TIMESTAMPTZ DEFAULT now()
);
ALTER TABLE conversations ENABLE ROW LEVEL SECURITY;
ALTER TABLE conversations FORCE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON conversations
USING (tenant_id = current_setting('app.tenant_id', true)::uuid)
WITH CHECK (tenant_id = current_setting('app.tenant_id', true)::uuid);
CREATE INDEX conversations_tenant_idx ON conversations (tenant_id, created_at DESC);
flowchart TD
REQ[HTTP request] --> AUTH[Auth middleware]
AUTH --> SET[SET app.tenant_id GUC]
SET --> APP[App + Prisma]
APP --> AGENT[AI agent SQL]
AGENT --> PG[(Postgres + RLS)]
PG -->|Policy enforced| ROWS[Only tenant rows]
// Express / Next middleware
import { prisma } from "@/lib/db";
export async function withTenant<T>(tenantId: string, fn: () => Promise<T>): Promise<T> {
return prisma.$transaction(async (tx) => {
await tx.$executeRawUnsafe(
`SET LOCAL app.tenant_id = '${tenantId}'`,
);
return fn();
});
}
SET LOCAL is critical — it scopes the GUC to the current transaction so pooled connections don't leak.
CREATE ROLE app_user NOINHERIT LOGIN PASSWORD '...';
GRANT USAGE ON SCHEMA public TO app_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;
Superusers bypass RLS — never connect your app as one.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
By default, table owners bypass RLS. FORCE ROW LEVEL SECURITY makes the policy apply to everyone except true superusers.
SET app.tenant_id = '11111111-1111-1111-1111-111111111111';
SELECT count(*) FROM conversations; -- only tenant A
SET app.tenant_id = '22222222-2222-2222-2222-222222222222';
SELECT count(*) FROM conversations; -- only tenant B
RESET app.tenant_id;
SELECT count(*) FROM conversations; -- 0 rows (or error if NOT NULL cast)
The WITH CHECK half ensures inserts also satisfy the policy. Without it, an attacker could write rows for a different tenant.
INSERT INTO conversations (tenant_id, agent_id, transcript)
VALUES ('22222222-...'::uuid, ...);
-- ERROR: new row violates row-level security policy
RLS is a transparent AND tenant_id = $1 appended to every query. Make sure every queried table has an index that leads with tenant_id.
CREATE INDEX conversations_tenant_created_idx
ON conversations (tenant_id, created_at DESC);
tenant_id = current_setting(...)::uuid is fine, but mismatched types silently disable index usage.OneRoof — CallSphere's property-management vertical — relies on RLS across 115+ DB tables to keep landlords from ever seeing each other's tenants, leases, or conversation history. Healthcare and Behavioral Health get the same treatment plus a separate healthcare_voice Prisma schema for HIPAA defense-in-depth; UrackIT layers RLS over Supabase + ChromaDB. 37 agents · 90+ tools · 6 verticals. Plans: $149/$499/$1,499 — 14-day trial, 22% affiliate.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
Q: RLS or schema-per-tenant? RLS for >50 tenants. Schema-per-tenant scales tooling badly past that.
Q: Performance overhead?
2-5% on indexed queries when policy uses current_setting + indexed column. Measure with EXPLAIN.
Q: Can RLS replace permissions in my app? RLS handles row visibility. App-layer authz still owns RBAC, audit logging, and rate limits.
Q: Does Prisma support RLS? Yes — set the GUC in a transaction, then call your Prisma queries inside it.
Q: How do I let admins see all tenants?
Use a separate role with BYPASSRLS, or include OR is_admin() in the policy.
Written by
Sagar Shankaran· Founder, CallSphere
Sagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
A founder's guide to the personal AI assistant market: best AI assistant apps, business-grade options, and how CallSphere's voice agent fits in.
A founder's guide to free AI agents, low-code AI agent builders, and how to know when you should pay for a real platform like CallSphere.
Graphiti is the open-source temporal knowledge graph for AI agents in 2026. Learn how bi-temporal memory beats vector RAG for voice agents and long-running LLMs.
Chatbot app vs ChatGPT in 2026: a founder's clear take on the difference, when to use which, and how a real AI chatbot app development works.
How we built a fault-tolerant HVAC emergency triage and tech-dispatch platform on Kubernetes — three-tier CQRS, 11 micro-agents on the OpenAI Agents SDK + LangGraph, NATS JetStream, DTMF/SMS/WebSocket acceptance, circuit breakers, and an evaluation pipeline that catches regressions before they wake a tech at 3 AM.
Head-to-head: OpenAI Frontier and Anthropic's managed agent stack — strengths, fit, and what each means for enterprise AI voice and chat deployment.
© 2026 CallSphere LLC. All rights reserved.
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.
Try Live DemoBook a DemoCalculate Your ROI