I've shipped fourteen Lovable apps in the last twelve weeks. Some of them are case studies on /labs. Most of them I built in a single sitting. The first half ate my weekends in a way I don't want to repeat. The second half didn't. The difference wasn't a better prompt. It was knowing where the ceiling was before I hit it.
If you've vibe-coded anything beyond a toy, you've felt the ceiling. It shows up at the same place every time. You're moving fast, the screens are appearing, the demo is real. Then something resists. The auth gets weird at the org-switching layer. The data stops persisting the way you expect. A workflow you triggered three times in a row creates two records and one duplicate. The model is happy to keep "fixing" it, but each fix introduces a new failure mode, and after the fourth round of "that's actually the right approach, let me also handle..." you realize you're not architecting — you're improvising.
That moment is the tax. And it's avoidable.
What vibe coding is actually good at
Before I trash it, let me be honest about why it works. For the first three hours of any greenfield project, vibe coding is the highest-leverage tool I've ever used. Not because the model is doing something magical — because it's compressing the boring parts of the loop:
- Schema and database scaffolding you'd normally write by hand. Authentic relational thinking, not pure spaghetti.
- Auth wiring for the common case (email/password, Google OAuth, one-tenant assumption).
- The deploy pipeline. Lovable hands you a live URL inside the first prompt. Replit and v0 are similar. That's not a small thing.
- UI scaffolding that would have taken half a day in Tailwind. You get to focus on the screen flow, not the markup.
- Validation — you can prove a customer cares about the idea before you ever open an IDE.
These are real wins. I'm not nostalgic for the world where I'd open a fresh Next.js project and burn the first afternoon on auth boilerplate. The platforms earned this.
The ceiling, and why it's there
The ceiling shows up because the model can only see what's in the code. It cannot see:
- What's not in the code — the implicit invariants, the race conditions, the "this user can never see this row" rule that lives in your head.
- Multi-tenant correctness — anything beyond one-org assumptions tends to compound bugs. Row-level security is exactly the kind of architecture decision that has to be made up front, not patched in.
- State that needs to persist server-side — sessions, drafts, background jobs, anything that survives a page refresh in a non-trivial way.
- Reliability properties — retries, idempotency, dead-letter behavior. The model will happily write fire-and-forget code that looks correct and silently drops work (the same bug I wrote about in Issue #152).
- Cost surfaces — that helpful "every time the user clicks this we call the LLM" pattern stops being cute at scale.
Each of these is a category of bug the prompt cannot fix because the prompt doesn't know about it. You can vibe-code your way around any single one. You cannot vibe-code your way around the architectural shape they're trying to tell you exists.
The 4-hour rule
This is the rule I now write down at the start of every Lovable session, on a sticky note next to my laptop. Four hours is the budget. If I'm still vibe-coding the same problem after four hours of cumulative work — the prompt is not the bug. The architecture is. Stop. Architect.
When to vibe vs when to architect first
★ Vibe code is the right move
- Validating a screen-flow idea with a real user
- Internal tool with one user (you)
- Demo for a sales call that won't get used in production
- The first 80% of a CRUD app with single-tenant assumptions
- Stitching three APIs together to see if the integration is worth pursuing
- Anything where being wrong costs you an hour, not a customer
★ Architect first, then vibe
- Multi-tenant from day one — orgs, roles, row-level security
- Anything touching money (payments, billing, payouts)
- Workflows that involve retries, queues, or background jobs
- Anywhere data integrity matters more than speed of delivery
- Public-facing forms that hit downstream systems (you'll silently drop leads otherwise)
- Anything where the cost of being wrong is a customer, not an hour
The line isn't vibe or don't. The line is vibe for validation, architect for production. The mistake operators make — and the one I made in the first half of this quarter's labs builds — is letting the prototype become the codebase. The prototype was meant to be discarded. Once you keep it, you've signed up for every future tax that prototype is going to charge you.
What the receipts say
The shift in your head
The reframe that made the difference for me: vibe coding is a discovery sprint, not a codebase. A discovery sprint produces three things — proof the idea works, a list of the hard problems, and a sketch of the architecture. It does not produce production code. If you treat your first 48 hours as discovery and budget a deliberate rebuild for the parts that need it, vibe coding becomes the highest-leverage tool in your stack. If you treat it as production from the first prompt, you'll pay the tax in a Saturday you didn't want to spend.
The platforms aren't lying when they show you a deployed app at the end of the first prompt. They're handing you a discovery sprint that happens to be deployable. The deploy is real. The discovery is what's actually valuable. What you do at hour four decides which one you remember a month later.