Table of contents
An Introduction to Vibe Coding
Writing software used to begin the same way every time: open an editor, recall the right API, type out the implementation. The skill being exercised was predominantly one of translation — turning a mental model into the exact syntax a compiler or runtime would accept.
That translation step is now optional.
Modern AI coding assistants can take a plain English description and return working code within seconds. The emerging practice of leaning into this capability — describing what you want rather than typing it out — has been called vibe coding. The term is informal, but the shift it describes is real: the primary act of programming is increasingly about communicating intent and evaluating results, not memorising syntax.
This article explains what vibe coding is, the principles that make it effective, how its workflow unfolds in stages, and where it shines versus where it can quietly burn you.
What Is Vibe Coding?
Vibe coding is a development style in which you direct an AI assistant — such as GitHub Copilot, Cursor, or Claude — using natural language, then review, test, and refine the generated output rather than writing every line yourself.
The name was coined by Andrej Karpathy in early 2025 to describe a mode of working where you are no longer fighting the editor; you describe the result you want, accept what looks right, tweak what does not, and keep moving. The "vibe" is in the flow: less friction, faster feedback, lower activation energy for new ideas.
It is important to be clear about what vibe coding is not:
- It is not "AI writes the whole thing while you watch." You are still the engineer — responsible for correctness, security, and maintainability.
- It is not a replacement for understanding. If you cannot read and evaluate the code the AI produces, you cannot safely ship it.
- It is not magic. The AI has no knowledge of your specific business rules, your production environment, or your colleagues' expectations unless you tell it.
A more precise framing: vibe coding shifts the bottleneck from typing to thinking and reviewing. The keyboard is no longer the constraint; your judgment is.
flowchart LR
A([Developer Intent]) -->|Natural language prompt| B[AI Assistant]
B -->|Generated code| C[Review & Test]
C -->|Looks good| D([Integrated Code])
C -->|Needs change| E[Refine Prompt or Edit]
E --> B
Concepts
Before going further, it helps to lock down the vocabulary. These terms appear constantly in discussions about AI-assisted development.
Prompt-Driven Development
Writing instructions for an AI in natural language rather than writing code directly. The quality of the output depends heavily on the quality of the instruction — which is why prompting is a skill in its own right, not just "talking to the computer."
Intent vs. Implementation
Intent is what you want to happen ("validate that the email field is not empty before form submission"). Implementation is the code that achieves it. In traditional development the programmer bridges the gap. In vibe coding the AI proposes a bridge and the programmer evaluates whether it is sound.
Iterative Refinement
The process of sending a follow-up prompt to adjust something in the previous output rather than re-writing from scratch. "Make the error message appear inline, not in an alert box" is a refinement. Good vibe coding is a conversation, not a one-shot request.
Context Window
The maximum amount of text (code, conversation history, file contents) an AI model can read at once. When a project grows large, not everything fits. Choosing what context to include — and what to leave out — directly affects the relevance and accuracy of the AI's output.
Hallucination
When an AI generates content that is confidently stated but factually wrong. In code this can mean an invented library name, a method that does not exist, or a subtly incorrect algorithm. Hallucinations look correct at a glance, which is why reviewing AI output critically is non-negotiable.
Core Principles
Effective vibe coding is not about typing less — it is about communicating better. These five principles separate productive AI-assisted development from chaotic prompt-and-hope sessions.
Describe, Don't Prescribe
Tell the AI the outcome you want, not the exact steps to get there. Prescribing implementation details — "use a for loop, iterate over the array, push items to a result array" — removes the AI's ability to find a cleaner solution and often produces exactly the code you dictated, no better.
Less effective: "Use Array.prototype.reduce to sum the prices field of each item in the cart array."
More effective: "Calculate the total price of all items in the shopping cart."
The second prompt lets the AI choose the most readable approach for the situation. You can always ask for a different approach if you dislike the result.
Iterate in Small Steps
Request one well-scoped change at a time. Asking the AI to "build the entire authentication system" in a single prompt produces a monolith that is hard to review and even harder to correct. Asking it to "add a function that hashes a password with bcrypt and returns the hash" gives you something small enough to read, test, and approve in thirty seconds.
Small steps also reduce the blast radius of a mistake. If a two-line change is wrong, the fix is obvious. If a three-hundred-line block is wrong, you may not even know where to start.
Stay in the Loop
Never let a session run so long that you lose track of what was generated. Read every significant block of code before accepting it. Run the tests. Check the edge cases. The moment you start rubber-stamping AI output without inspection, errors compound and become expensive to unwind.
Trust but Verify
AI assistants are optimised to produce plausible, confident-sounding output. They do not know your security requirements, your data contracts, or your team's conventions unless those are in the prompt. Treat AI output as a smart colleague's first draft — useful, worth reading, but not ready to ship without your sign-off.
Keep Context Focused
An AI with a cluttered or irrelevant context produces noisier output. When working on a specific module, include only the files, types, and documentation directly relevant to that task. Resist the urge to paste your entire codebase and ask the AI to "fix things." Focused context yields focused answers.
The Vibe Coding Workflow
Vibe coding unfolds in five repeating stages. The cycle does not need to be formal — in practice it feels more like a rhythm than a checklist — but understanding each stage helps you identify where a session is going wrong.
flowchart TD
S1["🎯 Stage 1\nFrame the Problem"]
S2["✍️ Stage 2\nGenerate a First Draft"]
S3["🔍 Stage 3\nReview and Test"]
S4["🔄 Stage 4\nRefine Iteratively"]
S5["✅ Stage 5\nIntegrate and Own"]
S1 --> S2 --> S3
S3 -->|"Needs work"| S4
S4 --> S3
S3 -->|"Acceptable"| S5
S5 -->|"New requirement"| S1
Stage 1: Frame the Problem
Before writing a single prompt, spend a moment clarifying what you actually need. A vague intent produces a vague output. Good framing answers:
- What is the exact behaviour I want?
- What are the inputs and expected outputs?
- Are there constraints the AI cannot infer (performance, library choice, existing API shape)?
- What does "done" look like so I can verify the result?
This stage does not require a long document. A few bullet points or a concise paragraph in your head is enough. The act of framing often reveals ambiguity you would have hit mid-implementation anyway — better to surface it before the AI starts generating code.
Stage 2: Generate a First Draft
Write the prompt and let the AI produce an initial version. At this stage, aim for a complete, runnable draft rather than perfection. Resist the urge to over-constrain the prompt with implementation details — give the AI room to make reasonable choices, then evaluate those choices in the next stage.
Provide relevant context: the function signature the output must conform to, the types already defined elsewhere, the library already in use. Without that context, the AI will make assumptions that may conflict with your codebase.
Stage 3: Review and Test
This is the most critical stage and the one most often skipped. Read the generated code as carefully as you would a colleague's pull request. Ask:
- Does it do what I described?
- Are there any edge cases it ignores?
- Does it handle errors?
- Is there anything I would not want in production — hardcoded values, unsafe operations, unnecessary dependencies?
Then run it. Unit tests, a quick manual smoke-test, or both. The goal is not perfection — it is establishing that the draft is a sound foundation before you invest more prompts in refining it.
Stage 4: Refine Iteratively
If the draft needs changes, write a focused follow-up prompt. Address one concern at a time. "The function does not handle the case where the input array is empty" is a better refinement prompt than "fix the bugs." Specific prompts produce specific, verifiable fixes.
Repeat Stage 3 after each refinement. It is common to fix one thing and inadvertently break another — tests catch this quickly.
Stage 5: Integrate and Own
Once the code passes review and tests, integrate it into the codebase as if you had written it yourself — because now you are responsible for it. Add comments where the logic is non-obvious, make sure naming conventions match the surrounding code, and delete anything the AI generated that is not needed.
This stage is also a mental handoff: the code is yours now, not the AI's draft. That mindset shift matters when something breaks at 2 a.m.
Once integrated, commit the change immediately — even if it is small. In vibe coding sessions, a commit acts as a checkpoint: a verified, developer-owned boundary before the next AI-assisted change begins. If a subsequent session produces something broken or hard to untangle, you have a clean rollback point. Treat each commit as a statement: "I read this, I tested this, I own this."
A Practical Example
To make the workflow concrete, here is a single feature worked through all five stages: a Python function that parses a CSV of transactions and returns the total spending per category.
Bad Prompt
"Write Python code for CSV transactions."
The AI has almost no information to work with. It will produce something, but whether it matches your mental model is a coin flip.
Good Prompt
"Write a Python function called
total_by_categorythat accepts a file path to a CSV file. The CSV has columns:date,description,amount(float), andcategory(string). The function should return adict[str, float]mapping each category to the sum of amounts in that category. Use only the standard library."
Now the AI has a function name, input format, column names, return type, and a library constraint. The output will almost certainly be useful on the first try.
import csv
from collections import defaultdict
def total_by_category(file_path: str) -> dict[str, float]:
"""
Parse a transactions CSV and return total spending per category.
CSV columns expected: date, description, amount, category
"""
totals: dict[str, float] = defaultdict(float)
with open(file_path, newline="", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
category = row["category"].strip()
amount = float(row["amount"])
totals[category] += amount
return dict(totals)
Refinement Round
After reviewing the draft, you notice it does not handle malformed rows — if amount contains a non-numeric string, float() will raise an exception. You send a focused refinement:
"Update
total_by_categoryto skip rows whereamountcannot be converted to float, and log a warning with the row number and the bad value using theloggingmodule."
import csv
import logging
from collections import defaultdict
logger = logging.getLogger(__name__)
def total_by_category(file_path: str) -> dict[str, float]:
"""
Parse a transactions CSV and return total spending per category.
Rows with non-numeric amounts are skipped with a warning.
CSV columns expected: date, description, amount, category
"""
totals: dict[str, float] = defaultdict(float)
with open(file_path, newline="", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row_num, row in enumerate(reader, start=2): # start=2: header is row 1
raw_amount = row.get("amount", "").strip()
try:
amount = float(raw_amount)
except ValueError:
logger.warning(
"Row %d: skipping invalid amount %r", row_num, raw_amount
)
continue
category = row["category"].strip()
totals[category] += amount
return dict(totals)
Two prompts, a working function with error handling, total time under two minutes. The developer's job was framing, reviewing, and deciding what to refine — not remembering the csv.DictReader API.
Advantages
Speed on familiar ground. Boilerplate, scaffold code, repetitive patterns, and well-understood problems can be drafted in seconds. The cognitive overhead of "what was that method name again?" disappears.
Lower barrier to unfamiliar territory. Exploring a language, framework, or library you have never used before is much faster when you can ask "write a minimal Express server that serves static files" and read a working example rather than digging through documentation cold.
Externalised working memory. You can describe a complex transformation in plain English and get code back, which is sometimes easier than holding the entire implementation in your head before writing the first line.
Rapid prototyping. Getting a proof-of-concept running in hours rather than days lets you validate ideas cheaply before committing engineering time to them.
Learning accelerator. Reading AI-generated code for an unfamiliar pattern — then questioning it, modifying it, and running it — teaches faster than passive documentation reading for many developers.
Reduced blank-page paralysis. Starting is often the hardest part. A first draft from the AI, even an imperfect one, gives you something concrete to react to.
Downsides and Risks
Confidence without correctness. AI output reads fluently and looks well-structured. This makes bugs harder to spot than in hastily typed code, because the surface polish masks the underlying error. A wrong algorithm in clean style is still a wrong algorithm.
Skill atrophy. Developers who rely entirely on AI for routine code may find that their ability to write that code independently erodes. This matters when you are working in an environment where AI assistance is unavailable, restricted, or simply wrong about something important.
Context blindness. The AI does not know your team's conventions, your existing abstractions, your data contracts, or your performance budget unless you explicitly include that information in the prompt. Omitting context produces technically valid but contextually inappropriate code.
Security blind spots. Subtle security issues — SQL injection through string interpolation, incorrect JWT validation, missing rate limiting — are easy to hallucinate in a plausible-looking implementation. AI does not know which data in your system is sensitive. You do.
Accumulating technical debt. Accepting AI output without critical review leads to inconsistent naming, duplicated logic, and unnecessary dependencies creeping into the codebase faster than they would with hand-written code. Vibe coding at high speed without regular clean-up creates a mess that is hard to untangle later.
Legal and licensing uncertainty. AI models are trained on large corpora of code. While the output is generally considered the user's work, the legal picture around AI-generated code is still evolving in most jurisdictions. For commercial projects, your organisation's legal team should weigh in on the policy.
quadrantChart
title Vibe Coding Risk vs. Benefit
x-axis Low Benefit --> High Benefit
y-axis Low Risk --> High Risk
quadrant-1 Use with caution
quadrant-2 Avoid or add strict review gates
quadrant-3 Fine either way
quadrant-4 Ideal vibe coding territory
Boilerplate scaffolding: [0.85, 0.1]
Prototype features: [0.80, 0.25]
Learning examples: [0.70, 0.15]
Core business logic: [0.60, 0.55]
Authentication code: [0.30, 0.80]
Cryptography: [0.15, 0.90]
Data migrations: [0.40, 0.70]
Vibe Coding vs. Traditional Development
| Dimension | Traditional Development | Vibe Coding |
|---|---|---|
| Starting point | Blank file or boilerplate | Natural-language description |
| Primary skill required | Syntax & API memorisation | Prompt crafting & critical review |
| Iteration speed | Minutes to hours per feature | Seconds to minutes per draft |
| Error responsibility | Developer writes the bug | Developer misses or accepts the bug |
| Best for | Precise, low-level systems work | Rapid prototyping & exploration |
| Worst for | Requires deep AI context | Safety-critical or regulated code |
Neither column is universally superior. Most real projects involve both modes in the same day: vibe code the scaffolding quickly, then hand-write the part where precision is non-negotiable.
When to Vibe Code (and When Not To)
| Situation | Vibe Code? | Reason |
|---|---|---|
| Throwaway prototype or proof of concept | Yes | Speed matters more than perfection |
| Learning a new language or library | Yes | AI output becomes a readable example |
| Boilerplate-heavy scaffolding | Yes | High repetition, low risk |
| Core business logic with complex rules | Careful | Must verify every assumption thoroughly |
| Security-sensitive code (auth, crypto) | No | Subtle bugs have severe consequences |
| Regulated domains (medical, finance) | No | Auditability and accountability are required |
The clearest signal to slow down and hand-write: when a bug in this code could harm a user, expose data, or be impossible to audit. Speed is not worth those trade-offs.
Conclusion
Vibe coding is not a shortcut that removes the need to understand software — it is a shift in where the effort goes. The hours previously spent recalling syntax and typing boilerplate move toward framing problems precisely, evaluating output critically, and refining iteratively.
The developers who get the most out of this style are those who treat AI output the same way a senior engineer treats a junior developer's pull request: read it carefully, ask questions, request changes, and take ownership of what gets merged. The AI is fast and broadly knowledgeable, but it has no stake in the outcome. You do.
Start with low-stakes tasks: scaffolding, one-off scripts, exploratory prototypes. Learn what the AI gets right without prompting, what it reliably gets wrong, and what it needs explicit context to handle well. Build up from there.
The vibe is in the flow. The engineering is still yours.
Summary
- Vibe coding means directing an AI assistant with natural language, then reviewing and refining the output rather than writing every line by hand.
- The five stages — frame, generate, review, refine, integrate — form a repeating loop. Review is the most important and most skipped step.
- Core principles: describe outcomes not implementations, iterate in small steps, stay in the loop, verify everything, and keep context focused.
- Key advantages: speed on familiar ground, lower barrier to new territory, rapid prototyping, and reduced blank-page paralysis.
- Key risks: confidence without correctness, skill atrophy, context blindness, security blind spots, and accumulating technical debt.
- Use vibe coding freely for prototypes, boilerplate, and learning; apply strict review for business logic; avoid it for security-critical or regulated code.
