All 5 AI packs for $39 →
← ToolTier Library
Cursor rules · Free

Cursor rules for Supabase (keys, RLS, auth)

A free Cursor rule (.mdc) for Supabase projects: publishable vs secret keys, Row Level Security on every table, getClaims() for server auth checks, and migrations instead of dashboard edits.

Install
.cursor/rules/supabase.mdc
Last tested
Cursor / supabase-js + @supabase/ssr · 2026-10-22

Most Supabase incidents in AI-built apps come from the same few mistakes: the secret key ending up in client code, tables shipped without Row Level Security, and server code that trusts a session cookie without verifying it. This rule tells Cursor's agent how to avoid each one. It's an Apply Intelligently rule (alwaysApply is false and there's a description), so the agent pulls it in when a task touches Supabase.

The key and auth guidance follows Supabase's current docs, checked on October 22, 2026: use the publishable key (sb_publishable_...) anywhere you ship code and the secret key (sb_secret_...) only on servers, since it bypasses RLS. Supabase is deprecating the legacy anon and service_role keys by the end of 2026. On the server, protect pages and data with getClaims(), which verifies the token, and never trust getSession() there.

It also explains how RLS failures look, because agents often misread them: a blocked select returns an empty result, not an error. And it forbids the usual bad fixes, like switching to the secret key or adding a using (true) policy. Building on Next.js too? The paid Next.js 16 pack adds 12 scoped rules, including data access, proxy and security. The Vibe Debug pack has a Supabase debugging guide.

supabase.mdc
---
description: Supabase keys, Row Level Security, auth checks and migrations. Use when touching Supabase clients, SQL, policies, auth or env vars.
alwaysApply: false
---

# Supabase: keys, RLS, auth and migrations

Stack: Supabase (Postgres + Auth) with `@supabase/supabase-js` and `@supabase/ssr`. If something here disagrees with the installed package's types or the Supabase docs, the docs win. Never invent a client method or config key.

## Keys: which one, where
- Browser, mobile, CLI or anything you ship: the **publishable** key (`sb_publishable_...`). It is public by design; Row Level Security is what protects data.
- Servers, Edge Functions, cron jobs and workers: the **secret** key (`sb_secret_...`). It bypasses RLS. It must never appear in client code, a `NEXT_PUBLIC_` variable, logs, URLs or source control.
- Env var names: `NEXT_PUBLIC_SUPABASE_URL` + `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY` for client code; `SUPABASE_URL` + `SUPABASE_SECRET_KEY` (no public prefix) for server code.
- The legacy `anon` and `service_role` JWT keys (long strings starting with `eyJ`) are being deprecated. Don't add new code that uses them. If the project still does, flag it; don't migrate keys without asking.
- Only create a secret-key client in files that can never be imported by client code (for a Next.js app, put `import 'server-only'` at the top).

## Row Level Security
- Every table in an exposed schema has RLS enabled in the same migration that creates it. No exceptions without a written reason.
- Write policies for the `anon` and `authenticated` roles. Scope them to the user with `(select auth.uid())`, never with a user id sent by the client.
- Separate policies per operation (`select`, `insert`, `update`, `delete`). `update` needs both `using` and `with check`.
- Remember how failures look: a select blocked by RLS returns **an empty result, not an error**; a blocked insert or update errors with "violates row-level security policy"; a missing table grant returns a permission error. Check grants before debugging policies.
- Never "fix" an RLS problem by switching to the secret key, disabling RLS, or adding a `using (true)` policy. Find which policy is missing and say so.

## Auth checks on the server
- Server code, including the Next.js proxy/middleware, protects pages and data with `supabase.auth.getClaims()`, which verifies the token.
- Never trust `supabase.auth.getSession()` in server code for authorization: it reads the cookie without revalidating it. Use `getUser()` only when you need a fresh user record from the Auth server.
- Keep the session-refresh proxy (`proxy.ts` on Next.js 16, `middleware.ts` on 15 and earlier) and return the response object it built, or users get signed out.

## Schema changes
- All schema changes go through migration files (`supabase migration new <name>`), committed with the code that needs them. No dashboard-only edits.
- Never edit a migration that has already run in a shared environment. Add a new one.
- After changing the schema, regenerate types (`supabase gen types typescript ...`) and use them in the client instead of hand-written row types.
- Ask before anything destructive: dropping tables or columns, `truncate`, `delete` without `where`, `supabase db reset` against anything but a local stack.

## Queries
- Select only the columns you need (`.select('id, title')`, not `select('*')` for user-facing data).
- Always check `error` before using `data`. Don't assume a query succeeded.
Want the full set?
Cursor Rules: Next.js 16

12 scoped Cursor rules, AGENTS.md and CLAUDE.md for Next.js 16.4 with Cache Components. This free entry is one file; the pack is the full multi-file set.

Get the pack ($9)
Works with: Cursor, Supabase
CursorSupabaseRLSSecurity

← More free rules, templates and prompts

+ Your logo here