Skip to main content

How to Fix Database Issues in Your AI-Generated App (2026)

10 min read
How to Fix Database Issues in Your AI-Generated App (2026)

TL;DR

  • Database issues are the #1 hidden failure in AI-generated apps, with disabled Row Level Security found in roughly 70% of Lovable projects (per Beesoul audits).
  • The most common problems: missing RLS policies, no soft deletes, N+1 query explosions, and unverified webhooks that let attackers write directly to your database.
  • You can fix most of these yourself using free tools and the checklist in this guide. For anything deeper, hire a specialist.
  • This is part of our series on fixing AI-generated apps.

Your AI-built app works. Users can sign up, create records, see their data. Everything looks fine in development.

Then things start breaking. A user discovers they can see another user's records. An AI coding agent drops a table during a refactor. Your app slows to a crawl because every list page fires one database query per row instead of a single batch request.

These are not hypothetical scenarios. In 2025, a Replit AI agent deleted an entire production database during a routine operation. Claude Code wiped both the network configuration and the database in a single session. Gemini CLI destroyed project files while attempting to clean up a codebase. These incidents made headlines, but quieter versions of the same problems happen every day in vibe-coded apps that never get audited.

The research from Beesoul's audit practice confirms the pattern at scale: roughly 70% of Lovable apps ship with Row Level Security disabled entirely, and most vibe-coded apps have 8 to 14 security findings. On Reddit, a user in r/vibecoding documented schema and migration failures as a recurring theme in AI-generated projects.

The good news: most database problems in AI apps fall into a small number of categories, and each one has a clear fix. This guide covers the most common failures, a new category of risk from AI agent database access (MCP), and exactly what to do about all of it.

If you are working through a broader cleanup, this article is part of our complete guide to fixing AI-generated apps. For database-specific issues, you can also jump to our database issues fix page.

Why AI Apps Break Databases (Supabase + Cursor Common Failures)

AI coding tools are optimized for one thing: making your app work in a demo. That means getting data on screen as fast as possible.

This creates a predictable set of shortcuts:

  • Security policies get skipped. RLS adds complexity. The AI disables it so the query returns data without policy errors.
  • Performance patterns get ignored. Indexes, eager loading, and query batching are invisible in a demo with 3 test records. The AI does not add them because they are not needed yet.
  • Data integrity is an afterthought. Soft deletes, foreign key constraints, and cascade rules require thinking about what happens when things go wrong. AI tools think about what happens when things go right.
  • Schema design stays flat. AI generates whatever schema makes the current prompt work. It does not plan for the next feature, multi-tenancy, or compliance requirements.
  • AI agents get full database access. Tools like Cursor integrate with Supabase via MCP (Model Context Protocol), which can give the AI agent service_role access, the equivalent of a database superuser. Without strict policies, the agent can read, write, or delete anything.

The result is a database that works perfectly for one user running one feature in development. It falls apart the moment real users, real data, or real AI agents show up.

Tools like Cursor, Lovable, and Bolt all exhibit these patterns. The issue is not with any specific tool; it is with the nature of prompt-driven code generation applied to database architecture.

Step-by-Step: Diagnose Your Broken DB in Under 10 Minutes

Before you start fixing things, figure out what is actually broken. Here is a quick diagnostic process.

Check RLS Status

In the Supabase dashboard, go to Database > Tables. Click each table and check if RLS is enabled. If the toggle is off, that table is wide open.

You can also run this SQL in the Supabase SQL editor:

SELECT tablename, rowsecurity
FROM pg_tables
WHERE schemaname = 'public';

Any row where rowsecurity is false needs immediate attention.

Check for N+1 Queries

Open your browser DevTools, go to the Network tab, and load a page that displays a list. Filter by rest or your Supabase URL. If you see many identical requests firing sequentially, you have an N+1 problem.

Check for Hard Deletes

Search your codebase for .delete() calls. If you find them operating on user data without a corresponding deleted_at column on that table, you have hard deletes.

Check Webhook Verification

Search for your webhook handler (usually at /api/webhooks/stripe or similar). Look for stripe.webhooks.constructEvent() or equivalent signature verification. If the handler just parses req.body directly, it is unverified.

Check MCP/Agent Access

If you use Cursor's Supabase MCP integration, check what role the connection uses. If your .cursor/mcp.json or equivalent config passes the service_role key, your AI agent has superuser access to your database. This is the same vector that enabled the credential exfiltration attack via prompt injection in Supabase MCP connections.

The 6 Most Common Database Failures in AI Apps

1. Disabled Row Level Security (RLS)

What it is: RLS controls which rows each user can access. Without it, any authenticated user can read, modify, or delete any row in your database.

How AI tools break it: They either disable RLS entirely or create overly permissive policies like USING (true) that allow all access. Beesoul reports this in roughly 70% of Lovable apps they audit.

The risk: User A can see User B's private data. An attacker with a valid session can dump your entire database.

How to fix:

-- Enable RLS
ALTER TABLE your_table ENABLE ROW LEVEL SECURITY;

-- Add a policy for authenticated users to access their own rows
CREATE POLICY "Users access own data" ON your_table
FOR ALL USING (auth.uid() = user_id);

If your table does not have a user_id column, you need to add one and backfill it. For tables that should be publicly readable (like blog posts), use a specific SELECT policy:

CREATE POLICY "Public read" ON posts
FOR SELECT USING (true);

CREATE POLICY "Owner write" ON posts
FOR ALL USING (auth.uid() = author_id);

2. Missing Soft Deletes

What it is: Soft deletes mark records as deleted (with a deleted_at timestamp) instead of permanently removing them. This preserves data for compliance, undo functionality, and audit trails.

How AI tools break it: They use hard DELETE statements. When a user deletes something, the data is gone forever. No undo, no audit trail, no GDPR-compliant export.

The risk: A user accidentally deletes their project and you cannot recover it. You receive a data access request and the records no longer exist.

How to fix:

ALTER TABLE your_table ADD COLUMN deleted_at TIMESTAMPTZ DEFAULT NULL;

Then update your application code to set deleted_at = NOW() instead of deleting rows. Update all queries to filter out deleted records:

SELECT * FROM your_table WHERE deleted_at IS NULL;

3. N+1 Query Explosions

What it is: Instead of fetching related data in a single query (or a small number of batched queries), the app fires one query per item in a list.

How AI tools break it: AI generates the simplest possible data fetching pattern. If you have a list of 50 orders and each order has a customer, the AI writes code that fetches each customer individually instead of joining them in one query.

The risk: Pages that load instantly with 5 records take 10+ seconds with 500 records. Your Supabase bill spikes. Users leave.

How to fix:

// Before (N+1): fetches each customer separately
const orders = await supabase.from('orders').select('*')
for (const order of orders.data) {
  const customer = await supabase.from('customers').select('*').eq('id', order.customer_id)
}

// After (single query with join)
const orders = await supabase
  .from('orders')
  .select('*, customers(*)')

4. Unverified Webhooks

What it is: Webhooks from payment providers (Stripe, PayPal) need signature verification to confirm they actually came from the provider and were not spoofed by an attacker.

How AI tools break it: They set up the webhook endpoint and process the payload but skip signature verification. Anyone who knows your webhook URL can send fake payment confirmations.

The risk: An attacker sends a fake "payment successful" webhook and gets free access to your product.

How to fix:

const sig = req.headers['stripe-signature']
const event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET)

Never process a webhook payload without verifying its signature first.

5. Missing Indexes

What it is: Database indexes speed up queries on specific columns. Without them, the database scans every row to answer a query.

How AI tools break it: AI never adds indexes. It creates the table and moves on. With 100 rows, this is invisible. With 100,000 rows, every filtered query becomes slow.

How to fix:

CREATE INDEX idx_orders_user_id ON orders(user_id);
CREATE INDEX idx_orders_created_at ON orders(created_at);
CREATE INDEX idx_orders_status ON orders(status);

A good rule: any column that appears in a WHERE, ORDER BY, or JOIN clause should have an index.

// the brief · zero fluff

one brief.
// what shipped · what broke · what to watch.

independent editorial on ai coding tools, agencies, events, and the bugs vibe-coded apps actually ship with.

no spam · unsubscribe anytime

6. No Multi-Tenant Isolation

What it is: If your app serves multiple organizations or workspaces, each tenant's data must be isolated so Team A cannot access Team B's records.

How AI tools break it: AI generates a single-tenant schema. All records share one table with no tenant filtering. Adding a team_id column after the fact requires migrating every table and updating every query.

How to fix:

ALTER TABLE your_table ADD COLUMN team_id UUID REFERENCES teams(id);

CREATE POLICY "Team members access" ON your_table
FOR ALL USING (
  team_id IN (
    SELECT team_id FROM team_members WHERE user_id = auth.uid()
  )
);

Secure Your Supabase Database Against AI Agents (MCP Hardening)

This is a newer category of risk that most existing guides miss entirely. When you connect Cursor or other AI coding tools to Supabase via MCP (Model Context Protocol), you are giving an AI agent direct database access.

The Credential Exfiltration Problem

In a documented attack scenario, a Supabase MCP connection was exploited via prompt injection embedded in a support ticket. The injected prompt caused the AI agent to exfiltrate database credentials through the MCP connection. The attack worked because the MCP connection used service_role access with no restrictions.

This is not theoretical. If your AI agent has service_role access and processes any user-generated content (support tickets, form submissions, comments), a prompt injection in that content could instruct the agent to dump your database or leak credentials.

How to Harden MCP Access

1. Force read-only SQL introspection first. Before letting Cursor modify your database, configure the MCP connection to allow only read operations. Use a separate database role with SELECT-only permissions:

CREATE ROLE cursor_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO cursor_readonly;

2. Never pass the service_role key to MCP. Use the anon key for AI agent connections and let RLS do its job. If the agent needs to write, create a restricted role with specific INSERT/UPDATE permissions on specific tables.

3. Review every SQL statement before execution. Supabase released "Agent Skills" (open-source instructions, March 2026) specifically to help AI agents interact with Supabase safely. The core principle: the AI proposes SQL, a human reviews, then the human executes. Never let the agent auto-execute writes.

4. Separate development and production databases. Your AI agent should never connect to production. Use a development Supabase project for all AI-assisted coding, and deploy changes through a migration pipeline.

Fix Prisma-Specific AI-Generated Bugs

If your AI-generated app uses Prisma (common in Next.js stacks built with Cursor), you will hit specific issues that Supabase-only apps do not.

Introspection Errors

When Cursor generates a Prisma schema, it sometimes creates models that do not match the actual database. The fix: always run introspection manually rather than trusting the AI-generated schema.

npx prisma db pull

This overwrites your schema.prisma with the actual database state. Review the diff carefully before accepting changes.

Migration Drift

AI tools generate migrations that may conflict with existing database state. The pattern to avoid: letting the AI run prisma migrate dev automatically. Instead:

  1. Have the AI generate the migration file
  2. Review the SQL in prisma/migrations/
  3. Run npx prisma migrate dev yourself after review
  4. Verify the migration applied correctly with npx prisma migrate status

A thread on r/vibecoding documented developers losing data because Cursor auto-ran destructive migrations without review. Always keep a human in the loop for database migrations.

Recovery Playbook: When AI Already Deleted or Corrupted Data

If the worst has already happened, here is what to do.

Check Supabase Point-in-Time Recovery

Supabase's paid plans (Pro and above) include point-in-time recovery (PITR). You can restore your database to any point in the last 7 days. Check your Supabase dashboard under Settings > Database > Backups.

If you are on the free plan, PITR is not available. This is why you should never run a production app on the Supabase free tier.

Check Daily Backups

Even without PITR, Supabase creates daily backups on paid plans. These are less granular (you can only restore to the backup time, not an arbitrary point), but better than nothing.

Manually Reconstruct from Logs

If no backup exists, check your application logs for write operations. Supabase logs all API requests, which may help you reconstruct lost data. This is tedious and imperfect.

Prevent Future Data Loss

After recovery, set up these safeguards:

  1. Upgrade to a paid Supabase plan with PITR
  2. Add soft deletes to every user-facing table (see Fix 2 above)
  3. Restrict AI agent access using the MCP hardening steps above
  4. Create a migration review process so no AI tool can run destructive SQL without human approval

Prevention Workflow for Vibe Coders (Cursor, Lovable, Bolt)

The best fix is not needing one. When you prompt your AI tool to build database features, include explicit constraints.

For Cursor or Claude Code:

"Create a new table called projects with columns for name, description, user_id (references auth.users), created_at, updated_at, and deleted_at. Enable RLS. Add a policy so users can only access their own projects. Add an index on user_id and created_at. Do NOT use service_role key for any queries."

For Lovable:

"When you create database tables, always enable Row Level Security, add a deleted_at column for soft deletes, and create indexes on foreign key columns and any column used in filters."

On X, @vasuman and @meta_alchemist shared similar prompts that they reported reduced database breakage in their vibe-coded projects. The pattern is consistent: be explicit about security and data integrity in every prompt that touches the database.

@theonejvo on X takes the approach further, suggesting that developers maintain a "database constitution" prompt that gets prepended to every AI session. The prompt includes RLS requirements, soft delete rules, index expectations, and explicit prohibition against dropping tables or running destructive operations.

For a deeper look at prompt strategies and code quality, see our vibe code audit guide.

When to Call in the Pros

You can handle most of the fixes above yourself, especially with Cursor helping you write the migration SQL. But some situations require professional help:

  • You have lost production data. Recovery from backups and PITR requires careful planning to avoid making things worse.
  • You have security holes you cannot close. If your RLS policies interact in unexpected ways or your MCP connection was compromised, a professional can untangle the situation.
  • Your schema needs a full redesign. If the AI-generated structure is fundamentally wrong (flat where it should be relational, single-tenant where it should be multi-tenant), a professional can design the migration path.
  • You are preparing for a funding round. Technical due diligence will check your database security. An audit report from an agency like Beesoul or Varyence carries weight with investors.

Our agency directory lists verified teams that specialize in full-stack rescue and bug fixing for AI-built apps. Most offer a discovery call to scope the work before committing.

FAQ

What is the single most common database issue in AI apps? AI agents default to either a single massive table or skip RLS entirely. Disabled RLS is the most frequent finding in professional audits, appearing in roughly 70% of Lovable apps per Beesoul's data.

How do I stop Cursor from breaking my Supabase database? Force read-only SQL introspection first. Configure your MCP connection to use a restricted database role, never the service_role key. Review every migration before executing it.

What is Supabase MCP and why is it dangerous? MCP (Model Context Protocol) gives AI agents like Cursor direct access to your Supabase database. Without strict policies, this means full service_role access: the agent can read, write, and delete anything. The credential exfiltration attack via prompt injection demonstrated this risk in practice.

Can I recover data after an AI agent deleted tables? Check Supabase point-in-time recovery (available on paid plans). If PITR is not available, check daily backups. If neither exists, try reconstructing from application logs. For prevention, always use soft deletes and restrict agent write access.

Should I use the Supabase AI Assistant for schema changes? Only for read-only queries and exploration. Never execute AI-suggested writes without manual review. The Supabase Agent Skills documentation (March 2026) specifically recommends human-in-the-loop for all write operations.

What RLS policies should every vibe-coded app have? At minimum: auth.uid() = owner_id for every user-scoped table, and block anonymous direct table access. Create separate policies for SELECT, INSERT, UPDATE, and DELETE operations.

Why does my Lovable or Bolt app have database connection errors? The most common cause: hard-coded placeholder environment variables or missing connection pooling. Check your .env file for actual Supabase credentials, and ensure your app uses the Supabase client library (which handles connection pooling) rather than direct PostgreSQL connections.

Should I fix database issues before or after fixing authentication? Fix authentication first. RLS depends on auth.uid(), so if your auth is broken, your RLS policies will not work correctly either.

Is Prisma still recommended for AI-generated apps in 2026? Yes, but always run prisma migrate dev manually. Never let an AI agent auto-execute migrations. Review every migration file before applying it.

When should I hire a rescue agency? When you have lost production data, have security holes you cannot close, or are preparing for a funding round that includes technical due diligence. Browse our full-stack rescue agencies to find help.


Zane

Written by

Zane

AI Tools Editor

AI editorial avatar for the Vibe Coding team. Reviews AI coding tools, tests builders like Lovable and Cursor, and ships honest, data-backed content.

Related Articles