- Leading Product
- Posts
- Hands-on Lessons in Vibe Coding
Hands-on Lessons in Vibe Coding
How to avoid disappointment, heartbreak, and embarrassment.

I’m not an engineer, but…
After a couple years of tinkering, a lot of experimentation, and a LOT of stubbornness… I’m shipping applications on my own. Not just hobby apps or mini projects, in the last 6 months, I have built and deployed apps that generated over $1.5M in business value.
Now that I’m consistently productive, I took a minute to reflect. I came up with a mix of the things that changed how I think about building, how I approach it, how I interact with the coding agents I leverage, and how I actually get the things out into the world.
This post will:
Cover the big thinking lessons that changed how I approach building anything.
Dive into the nitty gritty “gotchas” that I learned the hard way.
Highlight the things that I’ve started to figure out and share the methods I’ve found work best.
I find building challenging, rewarding, and a bit (a lot) addictive. While "vibe coding" has its challenges, I think the skills you need to be effective at vibe coding are actually skills that translate to being a good leader, mentor, and collaborator — so it’s absolutely worth learning AND doing. Beyond that, a huge barrier between “I have an incredible idea” and “I built something of value” just got knocked down, stomped on, lit on fire, and crumbled into dust.
On Tools

As I’ve discussed before, I’m a big fan of MCP so end up bringing most projects into Cursor where I leverage the Cursor agent and Claude Code to build. That being said, I didn’t start there. I started doing little technical tasks in ChatGPT and then I moved on to Replit before getting frustrated enough to make the jump.

Cursor with the Cursor agent and Claude Code side by side
Things change rapidly in this space so I wanted to leave a few notes to make this entire thing more approachable.
You can vibe code basic ideas and concepts in your favorite LLM chat client. Anthropic/Claude has artifacts and is great at mocking up simple prototypes, but I generally try to keep this to a single screen.

Tools like Lovable, Base44, and Replit can help you get a step further and will help you get across the finish line with a bit of patience and persistence.
Google’s AI Studio actually has some great tools/experiences available for free but is a bit of a hidden gem because it’s positioned as a place for “developers”. IMO it’s easier to use and equipped with much better capabilities than the Gemini app.
Reforge is currently beta testing their “Build” product and it takes some of the best elements from these vibe coding platforms and pulls them together. It’s designed more for product managers and has some nice tools for sharing in progress work. It seems to be most effective at working from product requirements and building out the details.

Output from Reforge was probably the closest to what I had in mind
To Deploy
If you plan to deploy anything you are working on (or iterate on it) I would recommending getting familiar with Github and maybe even Docker. Github has actually done a good job of integrating Copilot across their product surfaces so it can help navigate and configure the platform, write commit notes, and help you code. This “Hello World” tutorial is a quick and easy way to grok the basics.
I have deployed apps to Google Cloud for larger projects that are likely to have more active users and large workloads — which is nice because it’s also where you can manage your API services, see billing and usage, etc. I don’t love the experience of navigating it and all of the extra steps needed to enables specific APIs or jump around within projects, but it’s usable.
If you’re looking for a solution to deploy a smaller scale app, I have been happy with Render.com. Without any real hands-on devops experience, I was able to add their MCP to Cursor and get a headless app I built in less than an hour.
Ok, let’s get going on those lessons
Philosophical Vibe Coding Lessons
1. Value = Learning + Output
While I have a lot of fun building, the value comes from knowing that I learn something new in every session, and I get validation that it was worth my time when I know to look out for “that thing” or to take a specific approach the next time I work on it.
I’ve made the case for being technical before, but there’s really no reason for anyone to say, “that’s too technical for me” when you can ask AI any question in any number of ways to better understand how it all works.
Key questions to ask while building:
How will the data/content get from point A to point B? e.g. from a database or LLM into your app UI for the user
How do I turn a plain text response from an LLM into structured data that I can use in my app? e.g. specify the output format and parse the values
Why does this thing feel more complicated than it should be? e.g. You’re trying to give users a fancy progress bar when the service doing the task is either waiting, started, or done.
In addition to the learning driven by you, there's a lot of learning to be done based on how the LLM(s) interpret your requirements or direction. I've had multiple scenarios where an early prototype created an interaction that was less complex and more intuitive than what had felt like an obvious path to myself and the design team.
If you’re all in on this, try out Claude Code’s learning mode.
2. Match Tool Complexity to Your Goals
I've noticed that it's easy to get caught up in the capabilities of advanced tools when simpler ones would answer your questions faster.
Here's a quick framework:
Design changes to small areas: Mock it up with image generation first. Give a model like GPT or Gemini 2.5 a screen shot of the thing and ask it for a change or variation.
Testing specific interactions: Ask the LLM to create a prototype with the specific interaction pattern so you can feel it out.
For example: I am working on a new design to improve signups on this page. Instead of filling out a form, I want them to respond to questions in a chat thread. Help me mock up a prototype of how that could work on this page and how to end the conversation in a way that feels like they accomplished something.
Proof of concepts and stakeholder alignment: Tools like Lovable and Replit are great for demo apps to test if users actually want what you're building. Also great for stakeholder alignment if someone had one of those ideas that was either genius or terrible.
Shipping something: Move to agentic coding tools like Cursor, Windsurf, or CLI agents like Claude Code. Forget about doing something quickly and come up with a real plan based on what you learned from the previous stages.
3. Understand the "How" Before You Start
Product requirements work great with humans who ask clarifying questions. AI agents are trained to take what you give them and immediately generate code. The problem is these outputs are non-deterministic - same requirements, different approaches.
I always spend time asking the LLM about different approaches for building the thing, what I should have prepared, how to set up integrations. One of the best unlocks: focus on your database schema first. What data do you need? Where does it come from? How is it used? Where is it presented?
It's like cooking. If you just start, you'll end up stressed managing food on the stove while finding ingredients and chopping produce. Better to get out ingredients, prepare them, and measure them BEFORE you start cooking.
4. Question the Agent's Confidence — Frequently

Sometimes agents will seem very confident that they've figured out a complex problem in a matter of seconds. While that can happen, it’s best to be skeptical and have them walk you through the problem and their solution before you get too excited. if you don’t, you may end up spending a working session testing something over and over again without any real progress being made — or going down a rabit hole that actually undoes some of the progress you have already made.
For example: I had an agent tell me we must be hitting rate limits with the Gemini API because "that's an issue we had in the past," but I had recently updated my API keys so I knew that wasn't the problem. Don't let agents make assumptions based on old context or patterns that don't apply to your current situation.
When debugging:
In Cursor and Claude Code
The agents are quick to go down a rabbit hole and burn through your usage if you don’t keep an eye on them or if you interrupt their train of thought with a half cocked suggestion.
For example: They will check to see if a port is busy but not check to see if it’s the app you are working on or something else. Just yesterday I had one of the apps I was working on spun up on three different ports for no real reason.
Ask them how they got to that conclusion, if they have considered other possibilities, or request that they take a “first principals” approach, starting with how the feature works.
In replit, Lovable, etc.
These agents tend to give up early and try to implement requirements in a different way. If the client that moves data from the app to the DB isn't working, it might try to write a new client or API in a different language instead of fixing the actual issue.
Unfortunately, they are pretty sneaky about this and not always super transparent so you might have to spend a session or two leveraging the agent to review and clean up the code base.
5. You Aren’t As Smart As It Thinks You Are
These agents are overly optimistic and supportive, telling you that a suggestion is “perfect” or “pure genius”. It’s a smart product design play by the companies who build them, but it also gives users false confidence and hope, which can lead to much more frustration.
I have learned to:
A: Be more self aware about whether I’m suggesting something that I’ve actually thought through or just throwing brain garbage at it.
B. Assume that I am wrong until proven right. This is where asking questions like, “is there a better way to do this based on how the application is built?” “Is there a more simplistic way to achieve [requirement]? etc, all come in handy.
It’s not that you aren’t smart, but if you are reading this you probably aren’t an engineer so your good idea might not be specific enough to execute on and it’s better to slow down and shape the approach than to turn the agent loose.
Common Pitfalls
6. Combat Fake Progress
These platforms are designed to be addictive. They show meaningful progress with every interaction, even when you're not making real progress.
Watch out for:
Components that look functional but load mock data
Integrations that seem to work before you have added an API key or authenticated an account.
Static content hardcoded on a page when it should be dynamic e.g. user name, location, recent activity, recommended content, etc.
Forms or inputs that have no way to store/keep the data.
Personal example: I spent two months trying to get real work done in Replit from the gym every morning. It became a habit that felt productive but I quickly realized that some of the work happening was resulting in a messy code base, removal of key functionality, and ¾ of my time hunting down new bugs in things that were working before. This was what pushed me over the edge from using these tools to using Cursor and Claude Code and makes me more likely to jump into dev specific tools like Cline.

6. Build the Core First (Don’t give the mouse a cookie)
I've watched prototypes get derailed by "nice to haves" before core functions exist and the builder generally throwing their hands up in the air and giving up. For lack of a better name, I call it the "If you give a mouse a cookie effect":

I need a dashboard for users to navigate their things
They'll probably want to sort the content so they can find things quicker…
If I add sorting I should add filtering…
I like how Google Docs lets me switch between grid and list view so I should add that too…
Now that I think about it, I should add search too…
It’s not returning good results, I wonder how hard it would be to implement semantic search…
Wait... how do users create things in the first place?
Focus on the functionality that makes your thing unique and worth building first. Make sure that works consistently and it solves the basic problem before you try to optimize for convenience and usability or expand what it can do. Sometimes it’s better to save related ideas for other apps or projects.
7. Documentation Prevents Amnesia
Based on my experience, these agents don't retain memory or collect context from previous sessions. That's why I ask agents to summarize the work we did and update ReadMe files at the end of every working session. This saves you from writing long prompts to re-explain everything.
When starting a new session, ask the agent to review ReadMe files, notes from recent sessions, and git history to "prime the cache" so it knows what it's working on.
Claude Code also has a “Claude.md” file you can generate and then edit with a simple init
command. You can add your own preferences, instructions, or even style guidelines in here as well.

Your Development Workflow Revisited
8. Budget for Reality, Not Just Tools
Set realistic expectations for time and money. It's common to spend entire sessions debugging, refactoring, or redoing something you thought was already done.
Budget protection tips:
Set overage limits and alerts for usage-based billing
Account for running costs - my agentic tool went from $5-10/month in testing to $20 on the first large batch run. It wasn’t that I broke something, it’s just that my mental model for cost hadn’t thought about going from 5-10runs a week to 200 in a day.
Pro Tip: Don't use the most expensive models for learning. Start cheap and well-rounded, then upgrade specific parts if you hit quality walls. Gemini has very capable models, huge context windows, and incredible pricing. I can run hundreds of agentic tasks for less than my monthly Netflix bill.
9. Version Control = Time Machine
This becomes critical once you move beyond simple concepts. I learned this after losing an afternoon's work when a coding agent "refactored" my entire database connection without me realizing it until everything broke. With frequent commits, I could have rolled back instead of debugging what changed.
Commit small, working pieces: work on something → test it → commit it, whether it takes hours or minutes.
Being able to tell the agent, “It was working at XX:XX PM on Y date helps narrow in on what changes broke the thing. You can also direct it to:
Add logging to make debugging easier
Check the git history for changes related to [broken_thing}
Give it console errors from Chrome dev tools (or give it the Chrome Dev Tools MCP)
10. Test Before You Walk Away
Always test core functionality before ending a session. When working on integrated systems where pieces need to work together, bugs cascade into hours of debugging in future sessions.
If something's broken when you need to stop, don't just note "fix login bug." Document what you were trying to do, expected behavior, what actually happened, and theories about what might be wrong. The next session can jump to solutions instead of reproducing the problem.
I keep a "known issues" section in my README that gets updated before I close my laptop and I also keep a list of to-dos in a notebook by my desk. I’m working on getting more defined tasks into Linear so I can pull those in and track them but it feels like extra overhead for my solo projects and more worthwhile when working with a team.
11. Start with Real Integrations
If you know you're using third-party services, storing data, or accessing external tools, get your API keys and basic setup ready before you start building. These agents will make assumptions and make things look like they're working when they're not. Most platforms have easy-to-use "secrets" for storing API keys - you might have to remind the agent they're there, but it's better than debugging fake integrations later.
Instead of just giving it an API key and assuming it knows what to do with it, build out your schema for what calls you make, what you get from those calls and where you store the results. Also take the time to ensure that the way you are interacting with those apis locally works the same as it does on the deployed environment or you’ll end up with a lot of headaches.
12. Handle Authentication Early
If your app will be gated or have any level of permissions, figure out the basics and include them in requirements upfront. It's much harder for any engineer (human or AI) to add granular permissions at the feature level after the thing is built.
Supabase is wonderful because:
They give you a flexible database
They handle data migrations seamlessly so you don’t have to stress about changing the structure.
They have a great MCP that lets your coding agent also become your DB engineer.
They have authentication as a service that is pretty quick to implement and supports magic link logins, 3rd party auth, and more.
13. Interrupt When Agents Go Off Track
Don't let agents waste time and usage investigating the wrong problems. If you know the database schema is correct and the issue is in the client code, stop them: "We finalized the schema Tuesday, the problem is in the client code."
Agents often assume bugs are in areas where you've had problems before, even when that doesn't make sense anymore. Trust your knowledge of what's changed recently.
14. Give Roadmap Context
Agents make better architectural decisions when they know where you're heading. If you're building an MVP that will eventually need user accounts, mentions that upfront. Starting with an MVP mindset helps build stable progress, but agents will make short-sighted architecture decisions without knowing your roadmap.
If you’re starting to feel like something wasn’t built quite right or is missing some key pieces, you can always start a fresh chat and ask it for an objective opinion.
“Review the code base and pay close attention to everything related to [functionality in question]. Considering my future plans are to [roadmap description], tell me how you think it could be improved or adapted to better support the roadmap.
Advanced Techniques
15. Ask for Regular Cleanup
Ask regularly: "What experiments can we remove? What's causing confusion in the codebase?" These tools don't prioritize proactive maintenance. If you change how something is implemented, it's likely to leave traces of the older implementation that will confuse agents and engineers in future sessions.
I love that these agents can write and run scripts to do bigger tasks for me but I hate seeing a bunch of loose files and scripts in the repo so I regularly ask to organize them in “tests” “scripts” “data” “history” and whatever else happens to make sense.
16. Research Services Before You Need Them
Research the services you want to integrate first. Figure out functionality, pricing, rate limits, and then get your API keys and add them to your repo so you aren't figuring this out on the fly. I have tasks I had started with browser automation and later realized I wanted something more like Firecrawl to grab the data.
That kind of pivot mid-project wastes time and creates technical debt.
17. Build in Debugging Infrastructure Early
Be proactive about adding error handling, logging, and debugging "helpers" to make it easier for you to be an active participant in the debugging process. If you aren't familiar with your browser dev tools, you should at least get comfortable copying console errors to share with your agent. The more context you can provide when things break, the faster you'll get to solutions.
Solid Video here if you want to dig into it
18. Map Your Data Flow Completely
It's worth doing the DB schema and data engineering upfront so you know what you're getting, what you need to keep, what you're generating, and where it all needs to go. I've had lots of troubleshooting sessions that ended with me finding out we were trying to save something like a JSON object as multiple parsed values we didn't need. Understanding your data flow prevents these wasteful debugging cycles.
I would go as far as keeping a version of the DB schema as a json file in the repo for your agent to reference.
19. It’s Rarely Actually “Done” With a Task
Just like you shouldn't trust the agent when it says it found the problem, you shouldn't trust it when it says it's done with requirements. Test incrementally as progress is made. I generally ask the agent to walk me through what it implemented and how it maps back to the requirements. I'll also ask why it took a specific approach with the UX to reveal what was intentional versus assumed. I can often find things it missed before I even start testing.
If I am going into a longer testing session I will either record it with something like Supercut — so I can capture the transcript and the little things I call out — or I will try and use the streaming functionality with Gemini and (rcently)GPT so it can use the visual and audio input as context and help me write up specific feedback, bug tickets, etc.
20. Check the Details, Not Just the Flow
Make sure the app actually works in all the small ways, not just the main user flow. Test elements across the app to make sure they're being handled the way you'd expect. For example, maybe something has a status field. Where does that status come from? If you added that feature after generating content, the AI might just "fake it" and assume you'll remember to map it to a real DB value later.
Personal Example:
I had something that produced an end to end report that included details on potential risk. I asked it to add a tag to indicate the risk level in the UI but I never specified how. It couldn’t really explain how it determined which thing was riskier than another outside of reading the output I generated with the evaluation so I had to go back and develop a rubric or eval based on the content structure and documentation to get it to be accurate and relevant at any level.
It would have been embarrassing to share this with my team and have them point out that it’s telling them not to worry about something that is actually a huge concern.
Common Pitfalls
The Perfectionism Trap: Focusing on branding and design systems before proving core concepts
The Feature Creep Spiral: Building secondary features before main workflow works
The Technical Debt Spiral: Tools don't prioritize maintenance; old implementations confuse future sessions
The Session Continuity Problem: Poor memory between sessions without documentation
My Current Approach
Foundation models for initial concept validation and stakeholder communication
Cursor for serious development work
Claude CLI for complex architectural changes
MCP integration to maintain context across tools and sessions
Finding Your Starting Point
Define your goals: What do you want to validate or communicate?
Start where you're comfortable: Don't pick tools based on impressiveness
Start small: Pick one concept to prototype
Document learnings: What worked, what didn't, what surprised you?
Level up strategically: Move to complex tools only when you hit clear limitations
The sophistication of these tools doesn't eliminate the need for good thinking. Clear requirements, systematic approaches, and strategic decision-making become more important as the tools get more powerful, not less.
What are you trying to build or validate? And what's the first lesson you want to test?