postgres-rls-pattern

Enforce tenant-scoped Postgres Row Level Security with orgQuery wrappers.

1|Updated May 6, 2026
One-click install
npx skills add https://github.com/jacob-balslev/skill-graph --skill postgres-rls-pattern
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: postgres-rls-pattern
Source: https://github.com/jacob-balslev/skill-graph/tree/main/examples/projects/saas-stripe-postgres/skills/postgres-rls-pattern
Command: npx skills add https://github.com/jacob-balslev/skill-graph --skill postgres-rls-pattern

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve?

Prevents cross-tenant data leaks in multi-tenant SaaS by ensuring every Postgres query is automatically scoped to the current organization at the database security layer (Row Level Security), not just in application WHERE clauses.

Core Features & Use Cases

  • RLS policy triple coverage: Defines the full required set of safeguards using FORCE ROW LEVEL SECURITY plus matching USING and WITH CHECK logic to close gaps across SELECT/INSERT/UPDATE/DELETE.
  • Tenant-scoped query wrapper: Provides an orgQuery(orgId) transaction wrapper that sets app.current_org_id per statement via set_config, ensuring connection pooling does not cause tenant context bleed.
  • Safe service-role separation: Establishes when and how to use a systemQuery wrapper for legitimate cross-org operations (cron, admin, migrations) that must bypass RLS intentionally.

Quick Start

Use the postgres-rls-pattern skill to implement an orgQuery(orgId) wrapper and add RLS policies that enforce tenant scoping for every tenant-bound table.

Frequently Asked Questions about postgres-rls-pattern

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I prevent cross-tenant data leaks in a multi-tenant Postgres database?

Preventing cross-tenant data leaks in a multi-tenant Postgres database requires enforcing Row Level Security policies with a tenant-scoped query wrapper that sets the current organization ID per transaction, ensuring queries are automatically filtered at the database security layer rather than relying solely on application WHERE clauses.

Why does connection pooling cause tenant context bleed with Postgres Row Level Security?

Connection pooling causes tenant context bleed with Postgres Row Level Security when session variables persist across reused connections, but scoping each query inside a transaction with a set_config wrapper ensures the tenant ID variable is safely isolated per statement and prevents data leakage across tenants.

How do I configure Postgres Row Level Security policies for INSERT and UPDATE operations?

Configuring Postgres Row Level Security policies for INSERT and UPDATE operations requires FORCE ROW LEVEL SECURITY with matching USING and WITH CHECK logic tied to current_setting, ensuring tenant-bound tables validate that modified rows remain scoped to the current organization across all data manipulation commands.

Can I bypass Row Level Security for admin tasks in a multi-tenant Postgres SaaS?

You can bypass Row Level Security for admin tasks in a multi-tenant Postgres SaaS by using a separate service-role query wrapper, which intentionally skips tenant scoping for legitimate cross-org operations like cron jobs, migrations, and administrative tasks while keeping standard application queries fully restricted.

What is the best way to scope multi-tenant Postgres queries to a specific organization?

The best way to scope multi-tenant Postgres queries to a specific organization is using an orgQuery transaction wrapper that sets the app.current_org_id variable via set_config before executing each statement, guaranteeing consistent tenant isolation without modifying application query logic.

When should I use FORCE ROW LEVEL SECURITY instead of standard RLS policies in Postgres?

Using FORCE ROW LEVEL SECURITY instead of standard RLS policies in Postgres is necessary for multi-tenant SaaS systems when table owners must also be restricted by tenant scoping, ensuring every application query on tenant-bound tables is filtered by the current organization ID without exception.