Skip to main content

Row Level Security (RLS)

Row Level Security lets PostgreSQL enforce who can read and write each row — at the database level, not just in your application code.

This is critical for multi-tenant apps where multiple users store data in the same table, and it's a key requirement for NDPA 2023 compliance in fintech and healthtech apps.

Enable RLS on a table

ALTER TABLE orders ENABLE ROW LEVEL SECURITY;

Once RLS is enabled, no rows are returned by default until you add policies.

Create policies

Allow users to read only their own rows

CREATE POLICY "users see own orders"
ON orders
FOR SELECT
USING (user_id = auth.uid());

Allow users to insert only their own rows

CREATE POLICY "users insert own orders"
ON orders
FOR INSERT
WITH CHECK (user_id = auth.uid());

Allow users to update only their own rows

CREATE POLICY "users update own orders"
ON orders
FOR UPDATE
USING (user_id = auth.uid());

Allow public read (e.g. a product catalogue)

CREATE POLICY "products are public"
ON products
FOR SELECT
USING (true);

Service role bypasses RLS

Your service_role key bypasses RLS entirely — this is intentional for admin operations. Never expose it in client-side code.

Example: multi-tenant SaaS

-- Create a profiles table tied to authenticated users
CREATE TABLE profiles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
company_name TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);

ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;

-- Each user sees only their own profile
CREATE POLICY "own profile only"
ON profiles
FOR ALL
USING (user_id = auth.uid())
WITH CHECK (user_id = auth.uid());

Why this matters for NDPA compliance

With RLS enabled, even if a bug exists in your application code, the database blocks unauthorized data access. For fintech and healthtech apps handling Nigerian personal data, this provides a second layer of protection that satisfies NDPA 2023 data security requirements.

See NDPA Compliance →