Spec redesign / Supabase Studio

Deny by Default, the moment Postgres says no.

Row level security fails in silence. A wrong policy and no data look exactly the same: an empty array, and two hundred OK. This is a redesign of the screen where that starts, with a working prototype you can break yourself.

A spec redesign for Supabase · independent work, not affiliated

The film

Three and a half minutes, start to finish.

The editor as it is today, the research behind the redesign, and the proposed editor driven live. Everything on screen is the real prototype.

3 minutes 32 seconds Narrated Every screen is the working prototype, not a mockup

The prototype

Now open it and try to break it.

Everything in the film is live. The policy you build is evaluated by a real row level security interpreter over a sample table: grants first, then role, then the permissive union, then the restrictive intersection. Change anything and the result recomputes. Nothing is scripted.

  • 01Set Viewing as to a logged-out visitor. The editor tells you whether your policy never reached them, or reached them and matched nothing. Those are opposite bugs that look identical in production.
  • 02Under Advanced, choose Narrows every other policy. That reproduces the discussion that opens the film.
  • 03Untick the grant. A correct policy, and 42501 before any policy runs.
  • 04Pick Create, then set the row rule to every row. Watch it catch a policy that lets people write rows they do not own.
  • 05Flip to Studio today in the top right. Same task, current editor. The result panel disappears, because there isn't one.

Opens in a new tab. Best on a wide screen.

The proposed RLS policy editor, showing a live result panel beside the authoring form

The evidence

The rule isn't the failure. The silence is.

I pulled every GitHub discussion in supabase/supabase matching "RLS policy", filtered out the show-and-tell, and kept the ones where a policy is the actual subject. Then I coded each on its title and opening post.

438
threads coded
1,524
discussions mention RLS
405
issues mention RLS
4 yrs
since the top request was filed
PatternThreadsShare
Right policy, wrong identity. auth.uid() is null, the anon key was used, the token came from Clerk or Auth0, or the call ran server-side with no session.15034.2%
USING versus WITH CHECK. Mostly new row violates row-level security policy on insert.13430.6%
Grants, not policies. The policy is fine; the role never held the privilege.6013.7%
Expressing the rule at all. Multi-tenant membership, org scoping, joins.4911.2%
Policy combination. Two policies that each look right.4710.7%
Silent denial, named as the problem itself.388.7%

Silence is undercounted by design

At 8.7% it reads as minor. It isn't a category, it's the delivery mechanism for most of the others. A wrong identity, a missing grant and a restrictive policy all arrive the same way, so only the people who thought to name the silence itself show up in that row.

The ask hasn't changed since 2022

The most upvoted RLS thread in the repository asks for a way to test a policy. Its author described debugging as shooting in the dark. In April 2026 Supabase shipped an RLS Tester as a feature preview, then paused it while they re-evaluate its direction. This piece is scoped to that open question.

You have your policy as Restrictive type it needs to be Permissive. The entire fix, in one reply, thirty-four minutes after a developer asked why a correct-looking policy returned nothing. Discussion #33500.

The redesign

Five components, one loop.

The tester was the right capability in the wrong place. Verification you have to remember to visit is verification nobody does. So it moves inside the thing you were already doing.

Read from the source

Three things fixable tomorrow.

Independent of any redesign, found by reading PolicyEditorPanel at master. I'd happily open these as issues or pull requests.

01 / Defaults

With no target role selected the editor emits to public, and says so in its own helper text. The docs say to always name the role, and give the un-scoped form as the anti-example. The default is the thing the docs warn against.

02 / Templates

Six of the eight general templates carry no to clause. Two of them generate auth.uid() = user_id with no to authenticated. The same templates were corrected in 2024 to wrap (select auth.uid()). This is the same class of fix, unmade.

03 / Grants

The word "grant" does not appear anywhere in the policy editor, though grant failures are 13.7% of the coded corpus. The editor shows one half of Postgres's access-control model and no sign that the other half exists.

The constraints

None of this bends Postgres.

Silence is correct, and still designable. A policy that filters a row hasn't errored, it has filtered. Postgres is right to return nothing. But the dashboard can tell "no rows matched your filter" from "no rows survived your policy", because it can run the query twice and compare. The honesty lives in the interface, not the wire protocol.

Reads are silent. Writes are not. A missing grant and a failed with check both raise 42501. Only a using clause denies quietly. The prototype models all three separately, because conflating them overstates the problem.

USING and WITH CHECK are real semantics. One filters rows that exist, the other validates rows being written, and update needs both. Deriving that from the command and showing the result is different from hiding it. It is also what Supabase's CEO described in 2020, on an issue about an insert policy that wouldn't save.

Write previews need a transaction, not a special case. Running an insert under impersonation inside a transaction that rolls back gives a true answer with no side effects. Tables whose triggers call out are the real exception, and they're detectable ahead of time.

Made from the outside, on purpose.

This was built with no access to Supabase's internals: 438 coded public discussions as the research, Studio's own open source as the design system, and Postgres semantics as the constraint set. It's what I'd do in the first ninety days inside, shown from outside first. If it's wrong in places only an insider could know, that's the conversation I'd like to have.

I'm a UX designer and researcher specialising in accessible, explainable technical experiences. Previously: GDS-standard government services at MHCLG, published at CHI 2024, and Ledgerline, an explainable SME credit underwriting sandbox.

ishwaryasuresh97@gmail.com  ·  madeforhumans.tech