Why your Supabase bill spikes after adding RLS
RLS predicates run against every candidate row. Two mistakes make that catastrophic, and both look completely correct when you read the policy.
Rules that check this
- mediumRLS predicate column is not indexed
UNINDEXED_RLS_PREDICATE - mediumauth.uid() not wrapped in a subquery
RLS_UNWRAPPED_AUTH_CALL
The predicate column has no index
A policy filtering on `user_id` with no index on `user_id` degrades every query into a sequential scan of the whole table. It is invisible at a thousand rows and ruinous at a million.
VibeGuard reports one finding per table and column rather than per policy — three policies filtering the same column need one index between them, and three alerts would be three times the noise for one fix.
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_invoices_user_id ON public.invoices (user_id);
auth.uid() is called per row
A bare `auth.uid()` inside a policy is re-evaluated for every candidate row. Wrapping it in a scalar subquery lets the planner hoist it into an InitPlan evaluated once per statement.
The semantics are identical. On tables past a few thousand rows the difference is routinely ten to a hundred times.
-- Before: evaluated per row USING (auth.uid() = user_id) -- After: evaluated once per statement USING ((SELECT auth.uid()) = user_id)
Correlated subqueries count too
A call inside `EXISTS (SELECT 1 FROM members WHERE user_id = auth.uid())` is still per-row, because that subquery is correlated. VibeGuard flags it, and the fix is the same wrap.
Frequently asked
- Why CONCURRENTLY?
- It avoids taking a write lock on a live table. It cannot run inside a transaction block, so run that statement on its own.
- Does a composite index count?
- VibeGuard treats a column as covered if it appears in any valid index key. A leading position serves the predicate best, but demanding one produces more noise than it prevents.
- Is this a security issue?
- No, it is a cost and latency issue, which is why it is reported as medium rather than critical. It is the most common reason a Supabase bill grows faster than traffic.
Check your project in about ten seconds
Paste a URL. No signup, no writes, nothing stored.
Run the free audit