How We Made Our Supabase RLS Migrations Idempotent (And Why You Should Too)
The Problem You write a Supabase migration, it runs fine locally. You push to staging — fine. Then you need to re-apply it (rollback test, fresh CI environment, or a teammate cloning the repo) and ...

Source: DEV Community
The Problem You write a Supabase migration, it runs fine locally. You push to staging — fine. Then you need to re-apply it (rollback test, fresh CI environment, or a teammate cloning the repo) and suddenly: ERROR: policy "Users can view own stitched exports" for table "stitched_exports" already exists PostgreSQL's CREATE POLICY (and CREATE INDEX) doesn't have an IF NOT EXISTS guard. So if your migration runs twice, it blows up. This hit us in ClipCrafter when working on a new stitched_exports table. Here's the before: CREATE INDEX stitched_exports_project_id_idx ON stitched_exports(project_id); ALTER TABLE stitched_exports ENABLE ROW LEVEL SECURITY; CREATE POLICY "Users can view own stitched exports" ON stitched_exports FOR SELECT USING ( EXISTS ( SELECT 1 FROM projects WHERE projects.id = stitched_exports.project_id AND projects.user_id = auth.uid() ) ); CREATE POLICY "Service role full access to stitched_exports" ON stitched_exports FOR ALL USING (auth.role() = 'service_role') WITH C