Great Learnings from Vibe-Coding a Full-Stack SaaS
What I've learned in three months of building a low-complexity app from scratch with a completely new stack – and what you could find useful (if you're thinking about doing something similar).
![[object Object]](/_astro/a-renaissance-style-image-of-a-man-sitting-on-an-copy.DBYXzYTi_ZHf5rp.webp)
I probably stumbled upon the term vibe-coding some time in late February 2025, not so long after Andrej Karpathy posted his now-infamous tweet, which coined a great new term for programming without programming and really got the vibe-coding ball rolling. The idea really intrigued me: I’d planned to dive deeper into web development with React at some point, and now this moment seemed opportune.
It just so happened that my cousin and I had been kicking around an SaaS idea for a film location management app (she works in film) for quite a while, and that project always seemed a bit overwhelming to me. It would encompass learning a whole set of technologies all at once and building a rather complex app from the ground up – something I’d estimated would take me about 6–12 months, depending on how much time I could free up to do it.
Well, it turns out you can do a quite decent job in only three months, given you code like a maniac on AI steroids.
Here’s what I learned:
1. Keep it simple / context is king
Agentic AI is awesome for prototyping. You come up with your idea, and v0 will spit out a sleek dummy UI; you’ll ask Claude Code to add a feature to your app, and five minutes later you have it all working. However, in my experience, the AI does great at extruding seemingly working features but really starts to fall apart once you have even a low-complexity full-stack codebase with frontend, backend and database. It seemed like the complexity of it was simply too much for it – I would watch how the Cursor agent would just forget what the hell we were doing, get hung up on some minor details or even go off the rails entirely and end up an absolute fucking trainwreck.
After a while, adding even small features would often create new bugs because the AI had lost track of what exactly the API endpoint was supposed to be, had sent malformed data to the API, had forgotten that we were working in a Docker environment … you name it. Kevin Roose of Hard Fork fame once said that working with AI is kind of like having a very eager, genuinely savant coworker BUT he is also high on Ketamine like 20% of the time, and you never know when.
That’s pretty much how I felt: This thing knows everything about everything in IT, but then it will just get distracted about some really minor detail and blow the whole codebase up over it. Importantly, it also tends to lie with a straight face, as in “OK, I’ve gone and fixed this bug and now everything is working!“. You can’t really say it’s lying – after all, there is no it, and it doesn’t really have any grasp on reality besides predicting the next token – but if it were a junior dev, we would probably all agree that he simply lied that he solved problem X or Y.
The solution for me was to start giving it very clear context. I soon mostly stopped using the agentic modes of various apps and stuck to working in my IDE. I would clearly define what I wanted to do and pass 3–7 context files through VSCode to the ChatGPT app with o4-mini-high.
A sample prompt would go something like:
We need to rewrite this component so that when the user clicks here, it pushes the current state of the form to global state, dispatches and triggers a save. Here’s the component as well as the parent page.tsx, ProjectContext.ts and the API route file.
Once you make sure that the AI has all relevant files for the given process and give it clear instructions, it usually comes up with great solutions, and it’s fairly precise at implementing them. Of course, the drawback here is that you’re kind of leaving the paradise land of Vibe Coding and actually understand your codebase; that also being the upside: If you have to guide the AI all the way through implementing a new feature, you will actually understand what the fuck it’s doing, which is really useful when developing software.
2. Brainstorm ideas before implementing
One thing I found LLMs to be phenomenal at is giving you ideas, explaining concepts to you and suggesting best practices for your situation – especially in a stack you’re not familiar with.
Let’s say you want to implement a certain feature, like a map view of an object in your database. You can plug your db schema and the relevant page and component(s) into ChatGPT and explain what you’re planning to do. Then ask it for ideas on how to implement it, what would be best practices here, how these problems would usually be solved, and what would be the pros and cons of the available options.
AI usually did a great job (as far as I can tell) of explaining all these things to me, and answering any follow-up questions – right within the context of my app!
3. Use a well-documented stack, and do trivial things
Naturally, the more stuff has been written on the internet about your particular stack, the better the models will be at working with it since that is its training data.
HTML + CSS + JQuery? Node + Postgres + Express + React? Nextjs? Those things will fly to the moon with LLMs. Mobile apps and embedded software? From what I hear, it’s much worse at at that, and it makes sense.
Also, stick to solving rather trivial problems. My app fell firmly into React CRUD territory, with a few bells and whistles. That’s also something the LLMs are really good at: solving problems that have already been solved a thousand times on the internet. This is not to denigrate AI use, just to say that it likely isn’t very good at coming up with genuinely new things.
Another tech I’ve really been eyeing more and more the further I got into this whole quagmire was SaaS templates like Open SaaS, for a simple reason: The more you can preconfigure so that it works rock-solid, the more you will be able to vibe-code.
Take auth, for example: It took me two days to set up Clerk for my app (training data cutoff was October 2024, and there had been breaking changes in the package since). That should have taken an experienced engineer about 30 minutes, and, really, it would have been great to have that functional out-of-the-box in a template, in such a way that the AI couldn’t break it and would have to work around those narrow constraints.
Same goes for many other technical aspects: API set-up? Implementing Middleware? Setting up validation? Would have been great to just not have to do all of that myself, and fix it a thousand times over because, sure enough, the AI would break any of those mechanisms in an instant when left to its own devices. Instead, if I didn’t have to take care of that, I could work more on interesting stuff like implementing new features. But, again, I didn’t try any of the SaaS templates out there, so I can’t really pass any judgement.
4. Experiment with tooling
Different people have different working styles:
- Some people I’ve read online like to use a tool like repomix to pack the entire codebase into a file, then plug the whole damn thing into Gemini 2.5 Pro with its gigantic context window and get answers there.
- Other folks like the Cursor workflow and its YOLO mode – which I found exhilarating, but, over time, lacking (it felt to me like the background indexing and compression work Cursor was doing really contributed to LLM output quality degrading).
- For agentic workflows, I personally stuck with Code MCP for Claude Desktop (which is now basically obsolete since Claude Code comes included with your Pro subscription).
- But most of my work ended up being done in my IDE – the ChatGPT desktop app lets you pass on files you’re working on in another app. And by opening multiple windows or split-viewing files in VSCode, you can pass on as many as you like. The model can then generate edits with your prompt and context, and you can apply those to your files – and, in the meantime, check the edits for what they do (again, helpful for learning). Generally, that way you retain full control, keep your git in check, and keep your head engaged in the process.
I suspect that other people will feel much more comfortable just letting the agent run amok and iterating until it works; someone else might just use the AI for explaining stuff and prefer to type themselves. Different people will have different styles of working with AI, and I can only encourage you to try out different apps and modes to see what works best for you.
5. Learn how to git
That’s a pretty important one, and it’s basically required in any SWE context, not just for vibe coding. I’m not even talking advanced git acrobatics, just basic git stuff – setting up a repo and remote, pushing/pulling, stashing, resetting, and branching. Because, sure enough, agentic AI will nuke your codebase sooner or later, and knowing how to get back to where you were before is a basic survival skill out here.
It’ll also come in handy because the LLM will often go down some weird path you didn’t intend, and, again, just going back to the status quo ante should be easy to do. Which brings us to the next point:
6. Don’t get too attached to AI code
The sunk cost fallacy is real, and it won’t leave you alone even when you have an LLM eager to spit out infinite amounts of code 24/7. So be mindful:
- Recognize when the AI is headed down a wrong path
- Discard and reset the AI’s code edits if they don’t work / don’t make sense to you / aren’t what you asked for (good thing you learned git)
- Don’t get stuck for too long trying to make something work that doesn’t – it’s often better and faster to just reset back to your last working commit, then let the AI try its thing again
7. Point Deep Research onto your repo to look for security risks
This is actually a super useful tip: You can connect both ChatGPT and Claude to your GitHub repo so it has full access. From there, point the ChatGPT Deep Research feature on to your repo and ask it to look for any security vulnerabilities. A good prompt covering the essential stuff can be found here.
It’ll spit out a report after ~15 minutes that will highlight and categorize any obvious vulnerabilities in your codebase.
If you’re planning to sell your software to anyone, security should be pretty much top-of-mind, right after making a dope-ass product, so don’t underestimate how important this is. If you simply vibe-code your app into existence and slap it onto your VPS, automatic scanning tools will find vulnerabilities within a few days, compromise your server and abuse it for … crypto mining, actually. Trust me, been there ;)
8. Don’t forget to use your head
This is an important point, and one I’m still thinking about quite a bit. The problem is, with fairly powerful AI at your fingertips, it’s easy to lean back and let the LLM rip until you have a semi-working prototype held together by duct tape and chewing gum. However, you won’t have learned any software engineering – and that part still isn’t going anywhere. What might be disappearing (or at least diminishing) is the typing part, but you still need a working brain for small details such as:
- Figuring out what it is people need solved
- Coming up with a concept and a PRD
- Orchestrating the whole thing
- Wrangling the AI in the right direction
- Keeping track of where the project’s at
- Testing
- Considering edge cases
And ultimately, paying for the server, deploying, and taking accountability. As in: the AI coded your SaaS app, you put it online and charged money for it, it got hacked and people’s personal data got stolen, and now you’re being fined up your ass. Unfortunately, here remains an uncomfortable interfacing plane between the AI-supercharged future that’s already here, and good old-fashioned reality where you need to answer for your shenanigans.
In that sense, there’s still a gazillion things you need to learn, even if you don’t do any typing yourself – and that is exciting! Rarely in my adult life have I had so much new knowledge funneled into my old-school stone-age primate brain. AI is simply amazing at explaining IT stuff to you; it’s like having an omniscient super-experienced, highly senior software dev as a private tutor that never tires of your stupid questions, nor of the thousands of lines of logs or whatever you choose to feed into it.
The problem is, if you decide to vibe-code from scratch, you end up with a a lot of conceptual and architectural knowledge about how to build this thing – but very little precise muscle memory from actually typing React code into your IDE. You’re basically always one abstraction layer above the generations of coders that came before you, and I do suspect that something gets lost by not building code with your fingers.
Consider cooking as an example: You can have an erudite palate, read and know all about flavors, but there is some fundamental knowledge that can be gained only by chopping carrots and onions, by cooking up a good broth, by slicing sushi – it’s like you grasp the essence of what it is you’re cooking by letting it flow through your hands.
I think there is something similar going on with code, architecture, software engineering, whatever you want to call it. Some essential knowledge of what exactly it is you’re building can only be grasped by letting it flow through your fingers – and vice versa, as DHH put it, you can literally feel the competence drain out of your fingers when you use AI.
Since I’ve only done small coding projects before LLMs arrived, I can’t really speak to what it is I haven’t learned along the way. But I feel pretty confident that I’m simply nowhere near understanding as much as I would like to – and that I would be much more competent had I coded this thing with my bare hands, so to say.
Thoughts on where vibe-coding will go in the future
Those three months spent hammering out a PERN app until it was ready for testing have taught me a lot about the strengths and, more importantly, the limitations of AI for coding. So while I have a pretty clear look on that, I also don’t know much about the technical side of LLMs and where things might go in the future. So take my thoughts with a grain of salt.
These things are too stupid to make for a full-fledged SWE
Looking at X.com and Reddit, you can really get the impression that the hypebois might have a point when they claim that this website just built me a fully working Netflix clone with one prompt in three minutes. Well, they don’t really.
The AI I’ve seen in these months is capable enough to output a working todo app (which looks set to become the new hello world). Anything more complex and it falls apart.
While I can’t speak to the technical reasons for that, I find Yann LeCun’s argument quite compelling: LLMs are an amazing and very useful technology, but, in essence, they’re just trying to predict the next token. And if the next token prediction presents a probability P < 1 that the next token will be within the set of correct tokens, then that means that the model will always go wrong sooner or later when predicting more and more tokens, since it’ll be Pn with n tokens, which will converge towards 0. Thus, hallucinations and plain wrong answers are baked into this technology as an inescapable mathematical rule; scaling them with more training data1, a bigger model size or more compute – along with techniques like chain-of-thought – will only get you so far in trying to coax real, deep intelligence out of them. The underlying mechanism is still one of auto-complete, and thus it has little capacity for actual reasoning, planning, and memory.
A limiting, rigid structure would probably yield better results
Harking back to using an SaaS template like Open-SaaS, I think these models become much more capable if basic stuff is being set up for them (and can’t be broken by them). That, of course, limits the gamut of possible software to be written by LLMs, but it seems to me like giving it a clearly-defined, sandboxed structure in which to go wild would be a better approach. This is something I see in tools like Replit, which impose more limitations on the user, but require much less technical know-how and sifting through the guts of what the LLM wrote.
A few closing thoughts
I’ve had quite a blast developing the app, and it’s in closed beta testing (you can have a look at locman.io if you like, or drop us a line if you’d like to participate). I’ve learned an amazing amount of stuff about software engineering, and it’s been a really enriching experience, even if it was somewhat lonely nerding out on my computer for days on end.
However, I also end up wondering what I’ve lost along the way by opting to use AI extensively. It would probably have taken me thrice as long doing all of this manually, but I would probably also really know my shit (although knowing your shit seems very ephemeral in the software world).
So it seems like vibe coding can actually be a lot like majoring in philosophy – it’s exactly what you make it. You can plow through the process, threatening Claude with jail time, trying to get to your goal without thinking about it too much. Or you can use it to learn an awful lot about SWE principles and computational thinking. It can be both things, and both things are legit.
So try to view it as an opportunity to be used – or squandered, depending on how much curiosity you’re willing to bring to the table.
Footnotes
-
This is particularly relevant for SWE since you’re not quite limited by the data available on the internet or elsewhere. Instead, you can probably use synthetic data on a large scale since you can validate the LLMs answer against whether its code output is working or not, thus allowing it to self-supervise on synthetic data. ↩