FixRLSFixRLS
  • RLS Error
  • service_role Key
  • Publishable Key
  • Anon Key
  • MCP Setup
  • Blog
Supabase RLS: `USING` vs `WITH CHECK` Explained with Examples
2026/06/08

Supabase RLS: `USING` vs `WITH CHECK` Explained with Examples

Clear examples showing how USING and WITH CHECK answer different Supabase RLS policy questions.

Supabase Row Level Security is powerful, but two keywords confuse a lot of developers:

USING
WITH CHECK

They look similar.
They often contain the same condition.
But they are not the same.

This difference matters when your app starts throwing errors like:

new row violates row-level security policy

The mental model

Think of RLS as two questions.

USING

Which existing rows can this user see or touch?

WITH CHECK

What new or updated rows is this user allowed to create?

That is the core difference.


Example: user-owned projects

Suppose you have a table:

create table projects (
  id uuid primary key default gen_random_uuid(),
  user_id uuid not null,
  name text not null,
  created_at timestamptz default now()
);

Each project belongs to one authenticated user.

You want users to:

  • create their own projects
  • read their own projects
  • update their own projects
  • never access someone else's projects

SELECT uses USING

For reading existing rows:

create policy "Users can read their own projects"
on projects
for select
to authenticated
using (
  auth.uid() = user_id
);

This policy filters the existing rows the user can see.

If the row belongs to another user, it is invisible.


INSERT uses WITH CHECK

For creating new rows:

create policy "Users can insert their own projects"
on projects
for insert
to authenticated
with check (
  auth.uid() = user_id
);

This policy checks the row being inserted.

If a user tries to insert:

{
  "user_id": "someone-else-id",
  "name": "Wrong owner"
}

Supabase rejects it.

That is the right behavior.


UPDATE often uses both

For updates, you usually want both:

create policy "Users can update their own projects"
on projects
for update
to authenticated
using (
  auth.uid() = user_id
)
with check (
  auth.uid() = user_id
);

Why both?

USING says:

The user may update rows they currently own.

WITH CHECK says:

After the update, the row must still belong to them.

Without WITH CHECK, you can accidentally allow ownership changes.


DELETE uses USING

For deleting existing rows:

create policy "Users can delete their own projects"
on projects
for delete
to authenticated
using (
  auth.uid() = user_id
);

There is no new row to validate, so WITH CHECK is not needed.


Summary table

OperationUsually needs USINGUsually needs WITH CHECK
SELECTYesNo
INSERTNoYes
UPDATEYesYes
DELETEYesNo

This is not every possible case, but it is a useful default model.


Why AI-generated fixes can be risky

When developers paste an RLS error into an AI assistant, they often get a policy that looks plausible but is too broad.

For example:

create policy "Allow authenticated users"
on projects
for all
to authenticated
using (true)
with check (true);

This may make the app work.

It may also allow every signed-in user to access every row.

That is not a fix. That is a bypass.


A better approach

When writing RLS policies, avoid starting with:

How do I make this query pass?

Start with:

Who should be allowed to do this, and why?

Then translate that into:

  • USING for existing rows
  • WITH CHECK for new or changed rows

A tool I made for this

I built FixRLS because I kept seeing developers get stuck between Supabase docs, AI-generated SQL, and vague RLS errors.

FixRLS helps generate policy starting points, AI repair prompts, and proof-of-fix tests for common Supabase patterns.

It does not connect to your database and does not ask for keys.

Try it here:

https://fixrls.dev/new-row-violates-row-level-security-policy


Final thought

USING and WITH CHECK are not just syntax details.

They represent two different security questions:

  • Can the user access this existing row?
  • Can the user create or change a row into this state?

Once you separate those two questions, Supabase RLS becomes much easier to reason about.

Related FixRLS page

For this specific issue, use the matching FixRLS page: https://fixrls.dev/new-row-violates-row-level-security-policy

All Posts

Author

avatar for FixRLS
FixRLS

Categories

  • Supabase RLS
The mental modelUSINGWITH CHECKExample: user-owned projectsSELECT uses USINGINSERT uses WITH CHECKUPDATE often uses bothDELETE uses USINGSummary tableWhy AI-generated fixes can be riskyA better approachA tool I made for thisFinal thoughtOnce you separate those two questions, Supabase RLS becomes much easier to reason about.Related FixRLS page

More Posts

How I Fixed "new row violates row-level security policy" in Supabase
Supabase RLS

How I Fixed "new row violates row-level security policy" in Supabase

A practical mental model for fixing Supabase new row violates row-level security policy errors without bypassing RLS.

avatar for FixRLS
FixRLS
2026/06/06
Using Supabase MCP with Cursor and Claude Code Without Leaking Secrets
AI and MCP SafetySupabase Keys

Using Supabase MCP with Cursor and Claude Code Without Leaking Secrets

A practical checklist for using Supabase MCP with Cursor and Claude Code without leaking powerful secrets.

avatar for FixRLS
FixRLS
2026/06/16
Is It Safe to Expose Your Supabase Anon Key?
Supabase RLSSupabase Keys

Is It Safe to Expose Your Supabase Anon Key?

How to reason about visible Supabase anon keys, RLS policies, and what actually protects user data.

avatar for FixRLS
FixRLS
2026/06/10

Newsletter

Join the community

Subscribe to our newsletter for the latest news and updates

FixRLSFixRLS

Copy-paste RLS SQL, key guidance, MCP guardrails, and proof-of-fix tests before launch.

Independent tool. Not affiliated with Supabase. Not a scanner. Do not paste real secrets.

Fix Kit
  • RLS insert error
  • service_role key
  • publishable key
  • anon key exposed
  • Supabase MCP setup
Safety
  • Launch Safety Pack intent
  • Safety boundaries
  • Blog
  • GitHub examples
  • FAQ
Legal
  • Privacy Policy
  • Terms of Service
© 2026 FixRLS. All Rights Reserved.
GitHub