Skip to content

← Back to blog

The five vibe-coding antipatterns LovableForge catches every time

The five most common ways a vibe-coded Lovable app trips itself up — and how the LovableForge critique rewrites them before they ship.

16 Jun 2026

The five vibe-coding antipatterns LovableForge catches every time

We have run LovableForge critique over thousands of prompts. The same five mistakes show up in roughly 80% of them. None of them is the model's fault. All of them are prompt-shape problems.

If you fix these five before you paste anything into Lovable, your app will feel twice as solid for the same effort.

1. "Make it look like Linear"

A prompt that says "make it look like Linear" gets you a slate background, a sidebar, and a vague feeling of disappointment. The model has no idea which parts of Linear you mean.

Be concrete:

Dark background #0F172A. Indigo #6366F1 primary. Body text Inter. Headings JetBrains Mono Bold. Cards rounded-xl with a 1px slate-800 border, no shadow. Sidebar 240px, collapsible. Spacing tokens follow Tailwind defaults.

The rewrite is boring on purpose. Boring scales.

2. The single "App.tsx" page

The second the prompt says "build it in a single file", you have lost. The model will dutifully cram routes, fetch logic, types, and three components into one screen-tall file. The next time you ask it to add a feature, it will rewrite the whole thing and break something unrelated.

Tell the prompt where things live:

  • Routes in src/routes/
  • UI components in src/components/<feature>/
  • Server functions in src/lib/<feature>.functions.ts
  • Shared schemas in src/lib/schemas.ts

This costs you nothing and pays you back on every subsequent prompt.

3. Optimistic UI without rollback

"Make the like button optimistic" is a perfectly reasonable request. What you get is a counter that increments client-side and never reverses if the server says no. Now you have two users seeing two different counts and a support ticket you cannot reproduce.

Optimistic UI is fine. Optimistic UI without a rollback path on error is a bug. The prompt has to say so.

// Pattern, not a literal:
onMutate: async (newValue) => {
  await queryClient.cancelQueries({ queryKey });
  const previous = queryClient.getQueryData(queryKey);
  queryClient.setQueryData(queryKey, newValue);
  return { previous };
},
onError: (_err, _newValue, ctx) => {
  if (ctx?.previous) queryClient.setQueryData(queryKey, ctx.previous);
},

4. Empty states that say "No data"

The empty state is your best onboarding surface and most prompts waste it. "No projects yet" is not an onboarding flow. It is an apology.

Write the empty-state copy yourself in the prompt:

Empty state: a friendly heading ("Start your first project"), a one-sentence explanation of what a project is, and a primary CTA that opens the New Project dialog.

The model is happy to do this. It just will not invent the copy unless you ask.

5. Silent server errors

The number-one reason a Lovable app feels flaky in production is server functions that throw and the client only shows a toast that says "An error occurred". Specify the error contract.

On server error, return { ok: false, code: string, message: string }.
On the client, surface message in a toast. Log code to console. Never show "An error occurred".

Once you have a code, you can add quota-specific UX (code: "quota_exceeded" → open the upgrade dialog) without rewriting the whole flow.

Bonus: keep the prompt versioned

Every prompt change deserves a new version row. LovableForge creates one for you each time you click Apply on a critique issue. If you are doing this by hand, paste your old prompt into a prompts/ folder in your repo before you change it. Future you will thank you when the regression appears two weeks later.

Run any prompt through LovableForge once and you will see all five of these called out with drop-in rewrites. The whole point is to make the boring parts automatic so the fun parts stay fun.


Want LovableForge to run a critique like this on your own prompts? See pricing.