Skip to main content
ANODIZE
All insights

Data Engineering

Database Mistakes in Vibe-Coded Apps and How to Fix Them

An engineering guide to diagnosing and correcting common database design, integrity, security, migration, and performance mistakes in AI-generated applications.

15 minute readBy Anodize Labs

Database problems in generated applications often stay invisible during a demo. A table with a few rows does not reveal missing indexes, concurrent requests do not occur, and a single test user cannot expose broken tenant isolation. Once real data accumulates, small modeling shortcuts become correctness, performance, and recovery problems.

The solution is not automatically switching database products or adding an abstraction layer. First identify the application's invariants: who owns each record, which values must be unique, which updates must happen together, how records are deleted, and how much data key queries will scan. Then encode those decisions at the appropriate application and database layers.

Examples vary among relational, document, embedded, and hosted data services. The principles below remain useful, but exact constraints, transaction behavior, indexing, and backup capabilities must be verified for the selected system.

/01

Mistake 1: Letting the interface define the schema

Generated schemas often mirror form fields without modeling stable entities and relationships. This leads to repeated text, comma-separated identifiers, inconsistent status strings, and records that cannot be traced to an owner. Start with domain concepts and lifecycle rather than screens, then choose normalized relationships or deliberate denormalization based on access patterns.

Use stable identifiers, explicit timestamps, suitable data types, and documented nullability. Store monetary values in a representation that avoids floating-point surprises, and define time zones and units. Avoid a generic JSON column as the default for important searchable or constrained fields; flexibility can defer validation until data is difficult to repair.

/02

Mistake 2: Relying only on application validation

Two valid requests can race and create an invalid result even when each passed application checks. Database constraints provide a final defense for uniqueness, required values, references, and supported ranges. They also protect data written by scripts, jobs, migrations, or future services that bypass the original form.

Define constraints around business invariants and handle their errors as expected outcomes. For soft-deleted or tenant-scoped records, uniqueness may need a partial or composite design. Test with concurrent operations instead of assuming a read-then-write check is atomic.

  • Use foreign keys or an equivalent integrity mechanism for real relationships.
  • Add unique constraints for durable identities and idempotency keys.
  • Constrain status values and transitions rather than accepting arbitrary strings.
  • Make deletion behavior explicit: restrict, cascade, anonymize, archive, or soft-delete.

/03

Mistake 3: Treating record IDs as authorization

An unpredictable ID is not permission. A route that fetches a record by ID alone may expose it through logs, links, referrers, compromised clients, or enumeration. Scope every server-side operation to the authenticated owner, tenant, or an explicit access relationship, including reads, updates, deletes, exports, search, and file access.

Database-level row policies can add defense in depth when supported, but only if they are designed, tested, and used through correctly scoped credentials. Administrative service credentials often bypass those policies and must remain on trusted servers. Test isolation with multiple users and tenants, not only a privileged development account.

/04

Mistake 4: Ignoring transactions and idempotency

Critical workflows often span several writes: create an order, reserve inventory, record a payment event, and enqueue a notification. If these steps can partially succeed, define transaction boundaries and recovery behavior. Keep database transactions short and do not hold locks while waiting for slow external APIs.

External operations cannot usually join a database transaction. Use patterns such as idempotency keys, an outbox, compensating actions, and state machines to make retries safe and progress visible. Webhooks and background jobs should expect duplicate delivery and out-of-order events.

/05

Mistake 5: Shipping unsafe schema migrations

Generated migrations require review just like generated application code. Renaming a field may be represented as drop-and-create, a new required column may fail against existing rows, and a large index build may block traffic. Inspect both the intended schema and the exact operations produced by the tool.

For live systems, prefer backward-compatible expand-and-contract changes: add the new structure, deploy code that supports both forms, backfill in bounded batches, switch reads, and remove the old structure later. Back up before destructive work, measure lock behavior on representative data, and record how to stop or recover a failed migration.

/06

Mistake 6: Waiting for slow queries and connection failures

Indexes should follow real query filters, joins, ordering, and cardinality. Adding an index to every column slows writes and consumes space, while missing composite indexes can make ordinary list views scan an entire table. Capture query plans and timings with representative data rather than optimizing from intuition.

Connection behavior matters on serverless and horizontally scaled infrastructure. Calculate the possible connection count across instances, use a compatible pooler when needed, release connections promptly, and cap concurrency. Paginate unbounded lists, avoid per-row queries, and monitor slow queries, locks, storage growth, and pool saturation.

/07

Mistake 7: Calling a backup complete without a restore test

Confirm what the provider backs up, how frequently, how long backups are retained, and whether point-in-time recovery is available. Replication supports availability but does not necessarily protect against accidental deletion or a faulty migration because mistakes can replicate immediately.

Restore into an isolated environment on a schedule. Verify schema versions, row counts, critical relationships, access controls, and application workflows, then record elapsed time. Include object storage and external state in the recovery plan when the database alone cannot reconstruct the product.

Frequently asked

Questions about this topic.

Should I replace the database chosen by an AI coding tool?

Not automatically. Evaluate whether it supports required consistency, access controls, queries, scale, backups, portability, and team operations. Correcting schema and access patterns may be less risky than migrating products without a clear requirement.

Can an ORM prevent database mistakes?

An ORM improves consistency and developer ergonomics, but it cannot choose correct domain constraints, authorization, transaction boundaries, indexes, or recovery objectives. Review generated SQL and production query behavior when correctness or performance matters.

When should database performance testing begin?

Before launch, once important queries and approximate data shape are known. Seed representative volume, inspect critical query plans and connection usage, and continue monitoring because data distribution and workload change over time.

Have a product to ship?

Need senior engineering to take the next step?

Book an intro call