Vibe Coding Is Great Until It Hits the Database
By Mikhail Shytsko, Founder at Seedfast ·
You describe the app, the agent writes it, and for a while it genuinely feels like magic. Then you open the thing you built and every screen is empty. The dashboard shows no numbers, the list view spins and resolves to nothing, and the one account you can log in as has no orders and no history behind it. The code runs fine, which is the confusing part, because the real problem is the database, sitting there either as empty tables or filled with rows like user1@test.com and a product literally named "Test Product."
The vibe coding database problem is easy to misread, because two very different things hide behind that empty screen. One is structure, meaning the tables, columns, and relationships, and the agent handles that part well. What it fakes is the other half, the data meant to fill those tables, and a faked database is one you can't really test or show to anyone.
Here's the part that surprises people who've been hand-modeling databases for years. Coding agents are good at schema design. Describe a marketplace with sellers, listings, orders, and reviews, and you'll get back a set of tables with sensible types, primary keys, and foreign keys wired roughly the way you'd have drawn them. For a greenfield app, letting the agent draft the schema is a reasonable default, and it gets you to something running faster than modeling every table by hand.
An agent reliably gives you tables and columns, and gets shakier on the constraints, the rules that keep the data honest. Does orders.user_id actually carry a foreign key, or is it just an integer column named like one? The unique flag on email, the NOT NULL markers, and the delete rules all deserve the same suspicion, since cascading a user delete straight into their paid invoices is rarely what anyone wanted. This stuff reads as boring right up until the day it lets a broken row into your database, and that is exactly why skimming the generated migration yourself, for the two minutes it takes, is the highest-leverage review you'll do all week.
Migrations are where a lot of vibe-coded projects quietly rot, and the reason is nearly always the same. The agent changes the schema by running SQL straight against your database, adding a column here and dropping one there, all inside the conversation. It works in the moment, but a few days later the shape of your database lives only in a chat transcript you've long since scrolled past, with no clean way to rebuild it from zero or hand it to a teammate.
The fix here is a habit rather than a tool. Tell the agent that every schema change goes into a migration file, committed to the repo and applied with whatever runner your stack already has, whether that's Prisma Migrate, Drizzle Kit, or Django's migrations. Agents are happy to work this way once you ask, and they'll write the migration, name it, and run it. They won't hold themselves to the discipline, though, so that part stays with you. Once the migrations live in files, your database has a history you can replay, and the schema is no longer something only the current chat session remembers.
The genuinely hard part starts when you ask a coding agent to seed your database and it cheerfully writes a loop that inserts user1@test.com through user20@test.com, every one carrying the password password123, all created the same afternoon, none of them connected to anything else. The tables technically have rows now, but in practice you're left with a database that demonstrates nothing.

Two things go wrong, and they compound as the app grows. The first is realism, and real tables have spread in them, old accounts next to brand-new ones, a few heavy users with hundreds of records against a long tail with almost none, names and emails that vary the way real ones do. Placeholder data is flat, and flat data hides the exact bugs you'll ship, like pagination that breaks on page two, a query that's instant on ten rows and crawls on ten thousand, or a report that looks correct until one customer turns out to have zero orders. The distance between placeholder rows and realistic test data is most of what makes a vibe-coded app feel dead on arrival. Tidy little datasets tell reassuring lies, convincing precisely because everything inside is so uniform.
Consistency across tables is the second problem, and it only gets worse as the schema grows. Every order has to point at a user and a product that both exist. Add an order_item and it needs the order above it and a price beside it, while a review only makes sense if it belongs to someone who actually bought the thing. Holding all of that together is referential integrity, and it's the kind of bookkeeping a language model loses the thread of once the schema runs more than two or three levels deep. Neon tested this in the open, pointing AI models at synthetic data generation and watching them keep up while the schema stayed shallow, then drift once the foreign-key graph deepened and there was more to hold consistent than a model could carry in its head.
An empty database and a junk-filled one fail you in the same spot. You can't meaningfully test a vibe-coded app against either, because the tests pass whenever nothing in the data contradicts them, and you certainly can't demo it. No investor call or onboarding walk-through survives a product tour where every chart plots a single point and half the records read "Test Product."
Getting real data in takes a handful of steps, roughly ordered by effort.
Start with the reference data you keep by hand. The rows the app needs just to boot (roles, categories, plan tiers, country codes) are small, stable, and worth writing deliberately. Put them in a real seed file or a migration, keep them in version control, and let that be the one slice of your data you maintain yourself.
Everything else gets generated from the schema. The users, the orders, the content that makes the app look inhabited, none of that should be hand-typed or improvised row by row by the agent. Filling those tables is database seeding, and the durable way to do it is to have a tool read your schema and produce rows that fit it, rather than inventing values blind. A schema-aware generator looks at the structure you already have, the tables and columns and foreign keys, and generates data that satisfies it, so the orders reference real users and the whole set stays consistent without you wiring IDs together.
Don't fix the empty database by pointing the agent at a copy of real production data, tempting as that shortcut is. Past the obvious privacy problem, an autonomous agent with write access to a live production database is a blast radius you don't need this early in a project.
This is the shape Seedfast is built for. It's data infrastructure that reads your live schema and generates referentially consistent, realistic data from it in a single command:
seedfast seed --scope "marketplace with 200 sellers, listings, and orders"

Same screen, different database — the User 1 rows are gone and the top-listings panel finally has something to rank.
You describe the scenario in plain English, the same way you've been describing everything else to your agent, and the schema fills in the structure. Because it reads the database itself, it doesn't much matter whether Prisma, Drizzle, or something else defined your tables, and it runs against your application's database rather than being welded to one engine. When your next migration reshapes things, the following run picks up the new shape instead of breaking on the old one.
It fits vibe coding especially well because your agent can drive it for you. Seedfast is a CLI the agent can call like any other command, and it exposes an MCP tool an agent can invoke directly, so instead of writing you one more user1@test.com loop, the agent hands the relational work to something built for it and gets a full, connected dataset back. You stay in the same describe-and-iterate rhythm you started in, and the data stops being the weak link in the loop. For the agent-side mechanics, there's a full walkthrough of how to generate test data with AI.

Put the three pieces together and the database stops being the scary part of vibe coding. Let the agent draft the schema, but read the constraints before you trust them. Every schema change then goes through a migration file in version control rather than the chat window, and data gets a step of its own, a small reference seed you write by hand plus generated data for the volume. A database built that way comes up populated and consistent every time you rebuild it. You can run real tests against it, and when it's time to put the product in front of someone, it behaves like an app rather than a fixtures file.
Can Cursor or Claude Code set up my database?
Yes, for the structure. Cursor, Claude Code, Lovable, and Bolt are all good at drafting a schema and writing migrations from a plain-English description, and for a new project that's a fine place to start. Do check the generated constraints, the foreign keys and unique columns and NOT NULL rules and cascade behavior, because that's where agents are least dependable. Filling those tables with usable data is a separate problem, and it's the one they handle far worse.
How do I get realistic test data into a vibe-coded app?
Don't have the agent hand-write insert statements, since you'll end up with flat placeholder rows that don't line up across tables. Keep your true reference data, things like roles and categories and plan tiers, in a version-controlled seed file, and generate the rest from your schema with a schema-aware tool so the foreign keys and the distributions come out right. That gets you a database realistic enough to test and demo against without babysitting a seed script.
Why does my vibe-coded app look empty or broken?
Nearly always because the database has no usable data in it. Your code renders whatever the tables hold, so empty tables give you empty dashboards and blank lists, and placeholder rows like user1@test.com give you screens that technically load but show nothing convincing. The fix is usually to populate the database with connected, realistic data, not another round of edits to the application code.
Should I let the AI agent connect to my real database?
For a scratch or local database, go ahead. Be more careful with anything holding real user data, because an agent runs unattended and can do damage quickly, so the safer pattern is to hand it a disposable database seeded to look like production instead of production itself. There's more on keeping AI agents off production databases if you're weighing the trade-off.
Your agent can mostly take care of the schema and the migrations. Data is the piece that stays on you, and it decides whether the app you vibe-coded actually holds up when you test it or put it in front of someone. Seedfast is built to take that piece off your plate, so you point it at your schema, describe the scenario you want, and get realistic, connected data back for whatever database your app runs on. The 30-day free trial doesn't ask for a card, which means you can watch an empty database fill up before deciding it's worth keeping around.