# How to Stop AI From Wiping Your App's Database: A 7-Step Backup and Safe-Changes Guide for Vibe Coders

> 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: 2026-10-23 06:33:47+00:00

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.

One 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.

This 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.

`plan` column to `profiles`".` drop table` or `truncate`.
Here is what the official docs say, as of October 2026:

`db dump` command and maintain off-site backups."
Three gotchas apply almost everywhere:

Ask 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.

**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.

Save this as `backup.sh` in your project folder:

``` bash
#!/usr/bin/env bash
# Backs up roles, schema and data into a dated folder.
# Usage: DB_URL="your-session-pooler-connection-string" ./backup.sh
set -e
STAMP=$(date +%Y-%m-%d_%H%M)
mkdir -p "backups/$STAMP"
supabase db dump --db-url "$DB_URL" -f "backups/$STAMP/roles.sql" --role-only
supabase db dump --db-url "$DB_URL" -f "backups/$STAMP/schema.sql"
supabase db dump --db-url "$DB_URL" -f "backups/$STAMP/data.sql" --use-copy --data-only -x "storage.buckets_vectors" -x "storage.vector_indexes"
echo "Backup saved in backups/$STAMP"
```

Then keep it out of Git, because these files contain your users' data:

```
chmod +x backup.sh
echo "backups/" >> .gitignore
```

The connection string contains your database password. Never paste it into a public repo, a screenshot, or an AI chat.

**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.

On 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:

```
psql \
  --single-transaction \
  --variable ON_ERROR_STOP=1 \
  --file roles.sql \
  --file schema.sql \
  --command 'SET session_replication_role = replica' \
  --file data.sql \
  --dbname "PASTE-THE-NEW-PROJECT-CONNECTION-STRING"
```

Run 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):

```
select 'profiles' as table_name, count(*) from public.profiles
union all
select 'projects', count(*) from public.projects;
```

If 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.

Now 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.

The safest rule in this whole guide: **the AI builds against a dev database, never against production.**

`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.
Habit: before anything touches data, check which project ref is in your connection string or `.env`.

Raw SQL fired off by an AI leaves no record. Migration files give you something to read before anything runs. With the Supabase CLI:

```
# 1. Create a new, empty migration file
supabase migration new add_plan_to_profiles

# 2. Let the AI (or you) write the SQL into that file, then test it locally.
#    "db reset" here rebuilds your LOCAL database only.
supabase db reset

# 3. Compare local and remote migration history
supabase migration list

# 4. See exactly what would be applied, without applying it
supabase db push --dry-run

# 5. Only after a fresh backup (Step 2), apply it
supabase db push
```

Before step 5, read the migration file. You are not checking every line, just scanning for red-flag words:

```
drop table        drop column        truncate
delete from ...   (with no where)    alter column ... type
rename            db reset --linked  db push --include-all
migration repair
```

Two 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.

For 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.

**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**.

Prompt rules shape what the AI tries. Settings decide what it can do. Use both.

**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:

```
https://mcp.supabase.com/mcp?project_ref=YOUR_DEV_PROJECT_REF
```

If the AI must look at production, use a separate read-only connection:

```
https://mcp.supabase.com/mcp?project_ref=YOUR_PROD_PROJECT_REF&read_only=true
```

**Claude Code.** Add deny rules to `.claude/settings.json` in your project. Claude Code enforces these itself, whatever the model decides:

```
{
  "permissions": {
    "deny": [
      "Bash(supabase db push *)",
      "Bash(supabase db reset *)",
      "Bash(supabase link *)",
      "Bash(npx supabase db push *)",
      "Bash(npx supabase db reset *)",
      "Bash(psql *)"
    ]
  }
}
```

The `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.

**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.

**Everyone.** Add these rules to your `AGENTS.md`, `CLAUDE.md`, or Cursor rules file:

```
Database safety rules:
- Never run commands against the production database.
- Never run: supabase db push, supabase db reset --linked, migration repair,
  or any DROP, TRUNCATE, or DELETE without a WHERE clause.
- All schema changes go in a new file in supabase/migrations/. Stop after
  writing it and tell me what it does in plain English.
- Flag anything that deletes data, drops or renames columns, or changes types.
- Never ask me to paste database passwords or connection strings into chat.
```

`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.
Then 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.

To set up the workflow, paste this into your AI tool:

```
Read Supabase's guide "Automated backups using GitHub Actions"
(supabase.com/docs/guides/deployment/ci/backups). Create the periodic backup
workflow from that guide in .github/workflows/backup.yml, but trigger it only
on schedule (daily) and workflow_dispatch, not on push or pull_request.
Do not put any connection string in the file. Tell me exactly which GitHub
secret to create and confirm the repo must be private. Do not run anything.
```

`db reset` while linked to production.`--linked` it wipes the remote database.
Today:

`backup.sh` (or Lovable's export) and add `backups/` to `.gitignore`.
This week:

`db push --dry-run`, and back up before every push.
None 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.
