TL;DR

Vibe coding is a great way to turn an idea into a working prototype in an afternoon. But the term is now being applied to every kind of AI-assisted development, including production systems that need real engineering. Using one word for both is how teams end up shipping code nobody understands, can’t debug, and can’t safely change.

In this post you’ll learn:

  • What vibe coding originally meant, and how the term drifted
  • Where vibe coding is the right tool and where it quietly fails
  • The specific failure modes of unreviewed AI-generated code in production
  • What AI-assisted engineering looks like day to day
  • A short checklist for deciding which mode you’re in
  • How to keep your own skills sharp while leaning on AI

The word got bigger than the idea.

When Andrej Karpathy coined “vibe coding” in early 2025, he described a specific mode of working. You talk to an AI, accept whatever it produces, paste error messages back in when things break, and mostly stop reading the code. He framed it as fine for throwaway weekend projects.

That framing got lost fast. Today “vibe coding” is used for everything from a hobbyist building a habit tracker to a team shipping a payments integration with Copilot or Claude open in the next window. Those aren’t the same activity, and they shouldn’t carry the same label or expectations.

The problem isn’t the tool. The problem is that when everything is vibe coding, nobody has to say what standard the code is being held to.

Where vibe coding is the right call

I’m not here to bash it. Vibe coding is good at:

  • Prototypes and spikes: You want to know whether an idea is viable before investing in it.
  • Internal one-off scripts: A data migration you’ll run once, or a script that renames 400 files.
  • Learning and exploration: Seeing how an unfamiliar framework fits together by watching a model scaffold it.
  • Throwaway demos: Anything with a known expiry date.

What these share is low blast radius. If the code is wrong, the cost is small and visible. You can delete it and start over.

The moment code has users, data, money, or a maintenance horizon longer than a week, that logic stops holding.

Where it breaks

Here’s what goes wrong when unreviewed generated code reaches production.

  1. Code that works but isn’t correct: Models are very good at producing code that passes the happy path. Consider this endpoint, which is typical of what you get from a quick prompt:
app.get("/api/invoices/:id", async (req, res) => {
  const invoice = await db.query(
    `SELECT * FROM invoices WHERE id = ${req.params.id}`
  );
  res.json(invoice.rows[0]);
});
Enter fullscreen mode Exit fullscreen mode

It runs. It returns data. It also has a SQL injection hole, no authentication check, and no ownership check, so any user can read any invoice by guessing IDs. A demo wouldn’t reveal any of that. A security review would, and so would a person who read the code.

  1. Invisible architecture decisions: Every generated feature makes choices about error handling, data shape, retries, and where state lives. If you didn’t read the code, you didn’t make those choices, and you don’t know what they are. Six months later, someone has to extend the system and discovers three different patterns for the same problem.
  2. Debugging without a mental model: When production breaks at 2 a.m., “ask the AI” works only if the AI can see enough context to reason about the failure. Often it can’t. The engineer who has to fix it is now reverse-engineering code they never understood in the first place.
  3. Dependency and supply chain sprawl: Models happily add packages to solve small problems. They can also suggest libraries that are outdated, unmaintained, or, in rare cases, don’t exist at all, which is an opening for typosquatting. Nobody reviewed the choice because nobody was looking.
  4. Test theatre: Ask a model to write tests for code it just wrote, and you often get tests that confirm the implementation rather than the requirement. Coverage goes up while confidence shouldn’t.

None of this is unique to AI. Junior developers and rushed contractors produce the same problems. The difference is volume: AI makes it possible to generate unreviewed code faster than any team can review it.

Why the label matters

You might think this is just semantics. It isn’t, because names set expectations.

If a team says “we vibe coded this feature,” that tells reviewers, product managers, and future maintainers that the code is provisional. If the same team says “we built this with AI assistance and engineered it properly,” that signals the code was designed, reviewed, and tested.

When the first label gets applied to code that ships as the second, you get a gap between what people believe the system is and what it actually is. Incident reviews are full of that gap.

Being precise also protects the good version of AI-assisted work. Developers who use these tools carefully shouldn’t get lumped in with “just prompt and pray,” and the term has been dragged in that direction.

What AI-assisted engineering actually looks like

If vibe coding is “accept and move on,” engineering with AI is closer to working with a fast, tireless, occasionally overconfident pair programmer. In practice, that means:

  • You own the design: Decide the approach, boundaries, and data model before generating code. Give the model constraints: which patterns to follow, which libraries are allowed, how errors should be handled. A short spec in the prompt beats a long cleanup later.
  • You work in small steps: Generate one function or one module, read it, and run it. Large one-shot generations produce large one-shot problems that are hard to review.
  • You read every line that ships: Not skim, read. If you can’t explain what a block does, you don’t merge it. This is the single biggest dividing line between the two modes.
  • You write or at least specify the tests first: Tests that encode requirements before the implementation exists are far more trustworthy than tests generated afterwards to match it.
  • You keep the normal safety rails: Code review, CI, linting, static analysis, dependency scanning, and secret detection all apply to generated code. If anything, they matter more.
  • You use the model as a reviewer too: Ask it to find bugs, edge cases, and security issues in your code, or on its own. It’s often good at this, as long as you treat the output as leads to verify rather than verdicts.

Here’s the same invoice endpoint after an engineering pass:

app.get("/api/invoices/:id", requireAuth, async (req, res) => {
  const id = Number.parseInt(req.params.id, 10);
  if (!Number.isInteger(id)) return res.status(400).json({ error: "Invalid id" });

  const { rows } = await db.query(
    "SELECT * FROM invoices WHERE id = $1 AND owner_id = $2",
    [id, req.user.id]
  );

  if (rows.length === 0) return res.status(404).json({ error: "Not found" });
  res.json(rows[0]);
});
Enter fullscreen mode Exit fullscreen mode

A model can help write this. But a human had to know what to ask for and recognize what was missing.

A quick checklist: which mode are you in?

Before you start, answer these honestly:

  1. Will real users or real data touch this? If yes, it’s engineering.
  2. Will someone other than me maintain it? If yes, it’s engineering.
  3. Would a bug cost money, trust, or security? If yes, it’s engineering.
  4. Will it live longer than a few weeks? If yes, it’s engineering.
  5. Could I delete it tomorrow without anyone noticing? If yes, vibe away.

Notice that the answer isn’t about which tool you use. You can engineer with the same assistant you’d vibe code with. What changes is your process and your accountability.

It also helps to say the mode out loud in your team. A one-line note in a PR, like “prototype, not reviewed for production,” saves a lot of confusion later. Promoting a prototype to production should be an explicit decision with a rewrite or a full review attached, not something that happens because the demo went well.

Keep your own skills sharp.

One last risk is quieter than the rest. If you never read the code, debug it, or design anything yourself, those skills fade. The developers who will get the most out of AI over the next decade are the ones who can judge its output, and judgment comes from practice.

A few habits help:

  • Write the tricky parts yourself now and then, especially in areas you want to stay strong in.
  • Before accepting generated code, predict what it will look like, then compare.
  • Debug without the assistant sometimes, so you keep your instincts for reading stack traces and tracing state.
  • When the model does something unfamiliar, stop and learn why instead of moving on.

Conclusion

Vibe coding is a real and useful technique, and it deserves to keep its original meaning: fast, loose, disposable exploration where correctness isn’t the point. Everything else that involves AI and ships to users is software engineering, with all the responsibility that implies.

Use the right word, and you get the right behavior. Prototype freely, label it honestly, and when the work matters, slow down, read the code, and engineer it. The model can write the lines, but you’re still the one on call when they fail.

How do you draw the line on your team? I’d like to hear from you in the comments.