{"slug": "how-to-stop-ai-from-wiping-your-app-s-database-a-7-step-backup-and-safe-changes", "title": "How to Stop AI From Wiping Your App's Database: A 7-Step Backup and Safe-Changes Guide for Vibe Coders", "summary": "A developer published a seven-step guide for protecting production databases from AI coding agents, covering controlled backups, restore verification, a separate development database, and settings that keep agents away from production. The guide uses Supabase CLI dump and psql restore commands, with notes for Lovable Cloud and Replit, and stresses that Git cannot recover lost user data.", "body_md": "Your app has real users now. Their accounts, their saved work, maybe their payments all live in one database. And the same AI agent that builds your features can also run commands against that database.\n\nOne bad command, like a migration that drops a table or a \"reset\" pointed at the wrong project, can erase data you cannot get back. Git can undo code mistakes. It cannot undo lost user data.\n\nThis guide fixes that in an afternoon: a backup you control, proof that it restores, a separate database for the AI to experiment on, and settings that keep your agent away from production. The examples use Supabase, which many Lovable, Bolt, v0, Cursor and Claude Code apps run on, with notes for Lovable Cloud and Replit.\n\n`plan` column to `profiles`\".` drop table` or `truncate`.\nHere is what the official docs say, as of October 2026:\n\n`db dump` command and maintain off-site backups.\"\nThree gotchas apply almost everywhere:\n\nAsk yourself: \"If my database disappeared right now, what is the newest copy I could get back?\" If the answer is \"none\" or \"not sure\", do Step 2 today.\n\n**On Supabase**, use the CLI commands from Supabase's own backup-and-restore guide. You need the Supabase CLI and Docker Desktop installed (the CLI runs the dump inside Docker). Get the connection string from the **Connect** button on your project dashboard. Supabase recommends the **Session pooler** string by default.\n\nSave this as `backup.sh` in your project folder:\n\n``` bash\n#!/usr/bin/env bash\n# Backs up roles, schema and data into a dated folder.\n# Usage: DB_URL=\"your-session-pooler-connection-string\" ./backup.sh\nset -e\nSTAMP=$(date +%Y-%m-%d_%H%M)\nmkdir -p \"backups/$STAMP\"\nsupabase db dump --db-url \"$DB_URL\" -f \"backups/$STAMP/roles.sql\" --role-only\nsupabase db dump --db-url \"$DB_URL\" -f \"backups/$STAMP/schema.sql\"\nsupabase db dump --db-url \"$DB_URL\" -f \"backups/$STAMP/data.sql\" --use-copy --data-only -x \"storage.buckets_vectors\" -x \"storage.vector_indexes\"\necho \"Backup saved in backups/$STAMP\"\n```\n\nThen keep it out of Git, because these files contain your users' data:\n\n```\nchmod +x backup.sh\necho \"backups/\" >> .gitignore\n```\n\nThe connection string contains your database password. Never paste it into a public repo, a screenshot, or an AI chat.\n\n**On Lovable Cloud**, go to More > Database > Manage > Settings, click Export data, then Export and Start export. Lovable emails you when it is ready and saves it to your project's Storage. Download it and keep it somewhere outside Lovable, since its docs warn that removing the database deletes the export too. Download important Storage files separately from More > Storage.\n\nOn Supabase, create a new empty project to restore into. The Free plan allows 2 active projects, so this can be free. Install `psql` (the Supabase guide has instructions for Mac and Windows), then run the restore command from that guide, using the **new** project's connection string:\n\n```\npsql \\\n  --single-transaction \\\n  --variable ON_ERROR_STOP=1 \\\n  --file roles.sql \\\n  --file schema.sql \\\n  --command 'SET session_replication_role = replica' \\\n  --file data.sql \\\n  --dbname \"PASTE-THE-NEW-PROJECT-CONNECTION-STRING\"\n```\n\nRun it from inside the dated backup folder. Then compare row counts for your most important tables in both projects, using the SQL editor. Replace the table names with your own (`profiles` and `projects` are just examples):\n\n```\nselect 'profiles' as table_name, count(*) from public.profiles\nunion all\nselect 'projects', count(*) from public.projects;\n```\n\nIf the numbers match, you have a real backup. If the restore errors out, the Supabase guide has a troubleshooting section (for example, for errors mentioning `supabase_admin`), plus an extra key-copy step if you use Supabase Vault.\n\nNow delete this test project, because it holds a full copy of real user data. Create a fresh one and restore only `roles.sql` and `schema.sql` (leave out the `--command` and `data.sql` lines). That empty copy becomes your dev database in Step 4.\n\nThe safest rule in this whole guide: **the AI builds against a dev database, never against production.**\n\n`myapp-dev` and `myapp-prod`. Your local `.env` points at dev. Production keys live only in your hosting dashboard (Vercel, Netlify, and so on). Supabase also offers a local database (`supabase start`) and paid Branching.\nHabit: before anything touches data, check which project ref is in your connection string or `.env`.\n\nRaw SQL fired off by an AI leaves no record. Migration files give you something to read before anything runs. With the Supabase CLI:\n\n```\n# 1. Create a new, empty migration file\nsupabase migration new add_plan_to_profiles\n\n# 2. Let the AI (or you) write the SQL into that file, then test it locally.\n#    \"db reset\" here rebuilds your LOCAL database only.\nsupabase db reset\n\n# 3. Compare local and remote migration history\nsupabase migration list\n\n# 4. See exactly what would be applied, without applying it\nsupabase db push --dry-run\n\n# 5. Only after a fresh backup (Step 2), apply it\nsupabase db push\n```\n\nBefore step 5, read the migration file. You are not checking every line, just scanning for red-flag words:\n\n```\ndrop table        drop column        truncate\ndelete from ...   (with no where)    alter column ... type\nrename            db reset --linked  db push --include-all\nmigration repair\n```\n\nTwo deserve a special warning. Supabase's CLI docs say `db reset` with `--linked` or `--db-url` runs a script that drops all user-created entities in the remote database. And if `migration list` shows lots of local migrations with no remote match, stop: a push may try to apply old files you did not expect. One r/Supabase post from April 2026 describes exactly that, an agent running `db push` that replayed old migrations, including `DROP TABLE`, against a live project.\n\nFor destructive changes, prefer an additive version: add the new column, copy the data, switch the app over, and remove the old column later, after a backup.\n\n**On Lovable Cloud,** its docs say Lovable refuses changes like dropping or renaming a table or column, or changing a column's type, and adds to the database instead. That behavior is controlled by the agent permission **Execute backward incompatible database migrations**. Leave it at the default, or set it to **Ask each time** so you see the SQL first. Avoid **Always allow**.\n\nPrompt rules shape what the AI tries. Settings decide what it can do. Use both.\n\n**Supabase MCP server.** Supabase's docs offer two URL options: `project_ref` (limit it to one project) and `read_only=true` (run queries as a read-only Postgres user). Scope it to dev:\n\n```\nhttps://mcp.supabase.com/mcp?project_ref=YOUR_DEV_PROJECT_REF\n```\n\nIf the AI must look at production, use a separate read-only connection:\n\n```\nhttps://mcp.supabase.com/mcp?project_ref=YOUR_PROD_PROJECT_REF&read_only=true\n```\n\n**Claude Code.** Add deny rules to `.claude/settings.json` in your project. Claude Code enforces these itself, whatever the model decides:\n\n```\n{\n  \"permissions\": {\n    \"deny\": [\n      \"Bash(supabase db push *)\",\n      \"Bash(supabase db reset *)\",\n      \"Bash(supabase link *)\",\n      \"Bash(npx supabase db push *)\",\n      \"Bash(npx supabase db reset *)\",\n      \"Bash(psql *)\"\n    ]\n  }\n}\n```\n\nThe `npx` lines matter: Claude Code's docs explain that a rule only matches the command as written. The same docs say deny rules are not a full security boundary, so the dev project and read-only MCP still matter.\n\n**Cursor.** In Settings > Agents > Approvals & Execution, avoid **Run Everything**, which runs every command without approval. Auto-review or Allowlist are safer, but Cursor's docs say neither is a security boundary.\n\n**Everyone.** Add these rules to your `AGENTS.md`, `CLAUDE.md`, or Cursor rules file:\n\n```\nDatabase safety rules:\n- Never run commands against the production database.\n- Never run: supabase db push, supabase db reset --linked, migration repair,\n  or any DROP, TRUNCATE, or DELETE without a WHERE clause.\n- All schema changes go in a new file in supabase/migrations/. Stop after\n  writing it and tell me what it does in plain English.\n- Flag anything that deletes data, drops or renames columns, or changes types.\n- Never ask me to paste database passwords or connection strings into chat.\n```\n\n`SUPABASE_DB_URL` and commits the dump files. Supabase's guide warns: \"Never backup your data to a public repository.\" Use a private repo dedicated to backups.\nThen add a monthly calendar reminder, \"Restore drill\": restore the latest backup into a throwaway project (Step 3), compare row counts, then delete it. On the Free plan's 2-project limit, pause your dev project first. It is the only way to know your backups still work.\n\nTo set up the workflow, paste this into your AI tool:\n\n```\nRead Supabase's guide \"Automated backups using GitHub Actions\"\n(supabase.com/docs/guides/deployment/ci/backups). Create the periodic backup\nworkflow from that guide in .github/workflows/backup.yml, but trigger it only\non schedule (daily) and workflow_dispatch, not on push or pull_request.\nDo not put any connection string in the file. Tell me exactly which GitHub\nsecret to create and confirm the repo must be private. Do not run anything.\n```\n\n`db reset` while linked to production.`--linked` it wipes the remote database.\nToday:\n\n`backup.sh` (or Lovable's export) and add `backups/` to `.gitignore`.\nThis week:\n\n`db push --dry-run`, and back up before every push.\nNone of this slows you down. It just means that the next time an AI agent gets too confident with your database, you lose a few minutes instead of your users' data.", "url": "https://wpnews.pro/news/how-to-stop-ai-from-wiping-your-app-s-database-a-7-step-backup-and-safe-changes", "canonical_source": "https://dev.to/siteory/how-to-stop-ai-from-wiping-your-apps-database-a-7-step-backup-and-safe-changes-guide-for-vibe-23d7", "published_at": "2026-10-23 06:33:47+00:00", "updated_at": "2026-10-23 06:41:42.025604+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "ai-safety"], "entities": ["Supabase", "Lovable", "Bolt", "v0", "Cursor", "Claude Code", "Replit"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/how-to-stop-ai-from-wiping-your-app-s-database-a-7-step-backup-and-safe-changes", "markdown": "https://wpnews.pro/news/how-to-stop-ai-from-wiping-your-app-s-database-a-7-step-backup-and-safe-changes.md", "text": "https://wpnews.pro/news/how-to-stop-ai-from-wiping-your-app-s-database-a-7-step-backup-and-safe-changes.txt", "jsonld": "https://wpnews.pro/news/how-to-stop-ai-from-wiping-your-app-s-database-a-7-step-backup-and-safe-changes.jsonld"}}