---
title: Is My Vibe-Coded App Ready for Production?
url: https://varstatt.com/jurij/p/is-my-vibe-coded-app-ready-for-production
author: Jurij Tokarski
date: 2026-08-28
description: "Built in Lovable over a few weekends, liked by its first customers, with a key in the browser. Not ready yet, but fixable in place: a rebuild is the exception."
section: Blog (https://varstatt.com/jurij/archive)
tags: Q&A (https://varstatt.com/jurij/c/questions)
---

<Quote>
  I built our app in Lovable over a few weekends. Our first customers use it and like it. A friend who codes says our Supabase key is visible in the browser. Is it ready for more users, or do I rebuild it properly?
</Quote>

Not yet, and no rebuild. The gaps in an AI-built app repeat from app to app, and each one has a fix in place.

The friend found the first gap, or half of it. A Supabase key in the browser is harmless or an open door. It depends on which key it is and what stands behind it.

The customers who like the app are the part worth keeping. What's left is making it safe for the people who haven't signed up yet.

## It Works for Friends, Not Strangers

Production-ready means the app keeps working for people the founder has never met, and the founder hears first when it doesn't. My working definition is [Production Is Done](/principles/delivery/production-is-done): released to real users, with monitoring in place.

The first customers are friendly users. They follow the path the founder built, report a bug in a message and forgive a broken page. A stranger takes a path nobody tried, and some strangers go looking for gaps on purpose.

Hearing first comes from the setup, not from the users. Error tracking belongs in the first deploy, as in [Monitor Day One](/principles/diligence/monitor-day-one). Some bugs [never throw an error](/jurij/p/production-bugs-that-never-threw-an-error), and only a dashboard shows them.

The holes a stranger finds first are the same in almost every app the AI wrote end to end.

## Three Security Gaps Show Up Everywhere

The gaps are a key in the browser, tables without row-level security, and rules that don't check who's asking.

So is a vibe-coded app secure, and is Lovable safe? Maybe. The AI writes code that works, because working is what it was asked for. Security is what the code refuses to do, and nobody asked for that.

A founder once showed me a SaaS built by prompting alone. Within minutes I found [three security holes](/jurij/p/it-works-isnt-enough-for-commercial) that would have exposed customer data. Another app had its OpenAI key [sitting in the frontend code](/jurij/p/when-polish-over-security-costs-real) and no database rules at all.

The first gap is the key the friend saw. [Supabase](https://supabase.com) ships every app with a public key: the publishable key, or the anon key on older projects.

That one belongs in the browser. The secret key (the service role key on older projects), an AI provider's key or a payment secret never do. The browser's developer tools show which one it is.

The second gap decides whether the public key is safe. The browser talks to the database directly, and row-level security is the only thing between that key and every row. A table with it switched off answers anyone who holds the key.

The third gap hides inside the second. A policy like `using (true)` keeps row-level security on and lets everyone through anyway. A sound policy checks who is asking: deny by default, then open what each user needs.

The quickest test takes two accounts. Sign in as one and ask for the other's records. If they come back, the rules are open.

Closing the gaps means changing code, and that's where many AI-built apps get stuck.

## Why Each Fix Breaks Something Else

Nothing tells the AI what depends on the line it changes. Tests and small changes do.

The founder asks for one fix. The AI reads part of the code and fixes the bug in front of it. It also rewrites a little more than it was asked to, nothing checks the rest, and something else breaks.

The AI writes the visible part fluently: the screens, the forms, the path where everything goes right. The part underneath keeps a product alive: the data rules, the edge cases, what depends on what.

Human developers break things too. Three habits keep the damage small:

- Small changes: one fix per change, so a break points to the change that caused it.
- Checks on every change: types, a build and a few tests catch the break before a user does. [Quality Gates](/principles/delivery/quality-gates) puts TypeScript ahead of most unit tests.
- A way back: a [feature flag](/principles/delivery/feature-flags) turns a broken change off without a new deploy.

With those habits, the fix-and-break loop stops, and the rebuild question gets a short answer.

## Fix in Place, Rebuild by Exception

Each gap has a known fix, so fix it, almost always. A rebuild is for a data model that can't carry what customers ask for next.

A cleanup keeps what already works: the screens customers know, the data they've entered, the flows tested by hand.

A rebuild trades all of that for cleaner code. The new code is usually fine. The cost is the months when nothing ships while it's written.

Even a large fix stays a fix. Taking that exposed OpenAI key out of the browser meant moving the AI calls to a backend and adding database rules. The estimate was two to three weeks on an app that already ran.

When a rebuild does earn its place, the new version can run beside the live one. [One product's V1 and V2](/jurij/p/soapnoteai-v2-now-serves-100-percent-of-users) ran side by side for eight months.

[Should I Rebuild My App From Scratch?](/jurij/p/should-i-rebuild-my-app-from-scratch) covers the same choice for any codebase. An app built in a hosted builder raises one more worry: does fixing it mean leaving the builder?

## Keep the Tool, Own the Code

Keep Lovable or Cursor. Owning the code is the easy part. [Lovable](https://lovable.dev) pushes it to a GitHub repository in the founder's account, where any developer can open it.

The database matters more. A working Supabase backend can stay as it is, with its account and its bill in the founder's name.

On Lovable Cloud, Lovable's default backend, that account is Lovable's, not the founder's. No setting moves it: getting the database into the founder's own Supabase is a manual migration, so plan it before launch. [Who Owns the Code My Developer Writes?](/jurij/p/who-owns-the-code-my-developer-writes) has the full list.

Moving to [Next.js](https://nextjs.org) is a separate decision. It pays off when the app needs its own server, for example to keep AI keys out of the browser.

What lets the tools stay is the foundation under them: quality gates, small reviewable changes and feature flags.

On that V1 and V2 product, the designer polished the interface in [Cursor](https://cursor.com) or Claude Code, directly in the code. That worked because the foundation came first. [How Should My Team Use AI Coding Tools?](/jurij/p/how-should-my-team-use-ai-coding-tools) goes further.

Without that foundation, the second gap is common, and there's a public count of it.

## One Showcase App in Ten Was Open

In March 2025, the security researcher Matt Palmer scanned 1,645 apps from Lovable's own showcase. In 170 of them, about one in ten, anyone could read the data, and in some cases change it. Row-level security was missing or too loose.

He checked only their front pages. The flaw was published as [CVE-2025-48757](https://mattpalmer.io/posts/statement-on-CVE-2025-48757/) in May 2025.

Those apps worked for their makers too. More users means more strangers, and the two-account test finds the open door before one of them does.

## How I Rescue One in a Week

I use the same AI coding tools every day, so a rescue doesn't take them away. My [vibe code rescue](/x/founders/project-rescue) is one week. I read the code, the database rules, the keys and the deploys end to end, then move every account into the founder's name.

Then I stop the bleeding: leaked keys rotated, open records closed, the urgent break fixed. The week ends in a plan of what to fix, keep or rebuild, ranked.

Supabase sits outside my [default stack](/principles/delivery/default-stack), so I judge a Supabase app per project. The plan works for whoever comes next: me by the week, any developer, or nobody. The price is on the [homepage](/).

## What the Founder Should Do Now

One week of fixes: rotate the key, switch row-level security on, add error alerts.

The key comes first. If it's the publishable or anon key, it stays, and the work moves to the rules. If it's any other key, the call moves to a server and the key gets rotated, since the old one has already left the founder's hands.

Row-level security goes on next, for every table, with the two-account test against each one. Error alerts go in last, so the next failure reaches the founder before a customer writes in.

After that week, the founder keeps building in Lovable, one small change at a time, with checks on each. The app isn't a rebuild away from production. It's a week of fixes away.
