The Bible for Building Apps Without Coding
For those that follow me for my book reviews and similar content, this is completely unrelated. But don’t worry, this is a one-off content piece.
I’m not a developer, but I’ve successfully developed my first full-stack application using no-code tools and LLMs. In this article, I’ll share what I’ve learned from my journey into the world of no-code development. In this article, I will cover:
- The process of building my app with no-code tools
- The evolution of coding with LLMs
- Practical advice and guidelines
- Recommended learning resources
This is a detailed read, but I aim to provide context and value, equipping you with the knowledge I wish I had when I started. If you’re interested in exploring what you can build without a background in coding, this article is for you.
Building My App
I’ve always dreaded buying something new — a new mouse, new headphones, a new phone, and so forth. It always requires a ton of research that takes a lot of time. It’s never worth it, but I somehow end up getting sucked into it anyhow.
Last time I did this, it occurred to me that my research is rather repetitive, mostly reading online content, Reddit threads, and watching YouTube videos. So I figured this would be something that an LLM could replicate to an acceptable degree.
Of course, it’s never going to be as good. There are nuances of consuming the material that are difficult or impossible to pass off to an LLM: what’s a bad or good review, if the content is sponsored, if it’s AI-generated, and so on. But generally, I’m pretty confident the results are good enough for most things.
So recently I set to work trying to build this out. I thought it would be relatively simple: scrape the content I need, feed it into an LLM, and output the result. While this is indeed the overall flow, in practice it was much trickier. Regardless, after a lot of work, I eventually managed to do it. You can try it at https://owlreview.netlify.app/
Granted, this was mostly for fun and as a learning process. While it works great from my own testing, it’s quite possible that it has some bugs, doesn’t account for edge cases, or may break with heavy usage. I’m not at all interested in getting this perfect.
This is loosely how the app works: there are three research modes available:
- Researching a single product
- Researching alternatives to a product
- Finding a suitable product
After you pick what product you want, either as a standalone product for research or as the baseline to get alternatives for, you get an interface to pick what features you care about. You get an initial list of features that are standard for that product, but you’re free to add or remove them. You can also categorize the feature as either important or very important.
This is something that I always found quite important when deciding what product to buy that’s often underappreciated. It’s not just about if a product is good or bad, but if it’s good for your particular needs and requirements. Making and selling a product is often about trade-offs, and researching what product to buy is generally finding a product that made the right trade-offs for your particular situation.
After being halfway into the project, I wondered if someone had already built something like I was doing. I figured it was possible since the logic was simple, but maybe they didn’t include as many sources as I did. I was right to find similar projects, some even including more sources than I expected. But none of them had feature customization. IMO my project makes the research and recommendations way better because of this.
If you selected a multi-product research, it also suggests similar products to research. For instance, I may be thinking about buying a Razer DeathAdder mouse, but I’m still unsure if I should buy it or some other mouse. The app will find similar products and add them as suggestions to research, for example, Logitech G502 or Corsair M65. These are only suggestions, and similar to features, you can add or remove options.
After the app knows what products to research and what features you care about, it scrapes YouTube videos, online articles, and Reddit threads about each product. Then it aggregates everything and generates a final report with everything that it found, and a suggestion on what product to buy. For instance, if I deemed that the mouse sensor is very important to me, and it kept finding people complaining the sensor isn’t good, it won’t recommend my initial DeathAdder product but instead might recommend the product where people speak the highest about the sensor. But for someone else, they might not care about the sensor and instead prioritize ergonomics, for example.
It’s a rather simple app, but it still took me ages, and I learned a ton while doing it. There are countless things I’d like to improve on the app. The UI/UX is decent but not amazing, and the biggest limitation is speed. To generate the final report, it takes around 1–2 minutes. While still vastly better than hours of manual research, it’s nevertheless a big waiting time. I know some ways that I could make it faster and probably get it down to around 30 seconds, but I’d rather move on to something else. (It’s hard to make it much faster because there are many APIs being called)
A Guide for Building With LLMs
For those that find this interesting and want to build apps without knowing how to code, I’ll give a brief history of my journey so far, some of the things I learned, and how to go about doing this with the latest tools, some that are just weeks old.
Keep in mind that this is just my experience with coding, which is minimal all things considered. Therefore, take everything with a grain of salt; it’s quite likely that I butchered concepts, that I’m missing key nuance, or suggesting architecture that is very far from best practices. That’s unavoidable since I’m not an engineer. Although that’s precisely the point: how to build stuff without being an engineer.
It’s just my advice based on my experience and journey so far for those that want to walk a similar path.
Coding with LLMs
First, it’s important to remember how insane this concept actually is, and how unthinkable it would have been a few years ago. I also think it’s hugely important, and it will massively affect the startup world. The friction and resources needed to develop an MVP will go down 100x. Not only will software engineers be able to build such things much faster, but more importantly, non-technical people will be able to develop those MVPs themselves.
This will unleash tons of creativity that would otherwise be lost because those people would have no ability to get started or get someone to do it for them. This isn’t about replacing developers as a whole, which is generally quite silly, but for basic proof of concepts, this will have a massive impact.
I started playing with coding with LLMs almost since I started using LLMs in general, when LLMs started to get popular with GPT 3.5 at the end of 2022. However, the applicability of LLMs for coding back then was quite poor. Despite many viral TikToks or Twitter threads of full apps being built, this wasn’t actually the case. These were often clickbait with either misleading processes or just pure luck.
Despite that, you could still build some stuff, which I did. There were two basic ways of using LLMs for coding for someone who was not technical. The first was building basic frontends with HTML/CSS/JavaScript. For example, if you wanted a simple personal website, that was generally quite doable as long as its structure wasn’t complicated. I used CodePen back in the day, which was quite helpful because you could see the results of the code right away, which made it convenient to keep adjusting until you got it right. Although I later found JSFiddle, which is better.
The second, which I felt was hugely underrated, was building with Python. This actually worked much better than frontend, despite rarely seeing this mentioned online. You could build all sorts of scripts, and I did many of them. I have built over 20 or 30 at this point, and I still use them from time to time. You can do this locally, but I think Google Colab is an amazing tool and it’s where I’ve built most of my scripts. It’s super beginner-friendly as it requires nothing of you except to create a file and paste the code from GPT.
Next Generation of LLM Coding
There were two major problems with the setup above. First, the frontend often wasn’t great looking, at least out of the box. One great advancement was V0, which I honestly think changed frontend forever. It uses React with Tailwind and Shadcn, and it looks amazing almost right away. This has made a massive difference for building good-looking websites with little or zero technical knowledge.
The other problem was that you could either build a backend or a frontend, but they were also isolated and disconnected. With frontend you’re quite limited because you can’t call any external data or store any data in any efficient way. And almost any app you can think of becomes impossible to build like this. The backend has the opposite problem: you can easily call whatever API you want and store data, but this environment is restricted to you, and there isn’t a way for others to interact with it.
You can of course build a proper app with a backend and a frontend, and that’s how developers have always done it. The problem is that for those that weren’t technical, this was incredibly hard to do. Everything related to backend beyond simple scripts as the ones I mentioned above is much harder, and much more complicated than a simple JS webpage by several orders of magnitude. There is tons of setup, many things you have to understand conceptually, and much greater complexity. Even getting it running is close to impossible if you’re new.
Cursor AI was also a huge game-changer, but it didn’t fix this fundamental problem of a full-stack app, and it was more for changing existing code rather than building it from scratch. While super helpful, I felt that the benefit was more towards developers who could now code faster rather than allowing non-developers to get further than they already had with existing tools and LLMs.
Luckily, this all changed with the amazing work of StackBlitz, who recently launched Bolt. In many ways it’s similar to V0 and has a similar interface, but it actually has a functional backend. In my opinion, Bolt was the first time that making full-fledged apps, in this context defined by being a full-stack application with a backend and frontend, was feasible for casual users.
The Ideal No-Code Flow
Even though Bolt has changed the game massively, I would still recommend getting started exactly as I did: building basic frontend websites with JS to get a feel for it, and then build some basic Python scripts to automate some tasks. I feel this gives you a decent understanding of how these things work, and you can still build some very cool stuff with it. Think of problems that you have that could possibly be automated if you had a dedicated team of engineers to build whatever you want. Then out of all those problems, figure out which ones are simple and feasible for you to do, and then just give it a shot.
Either way, if you want the absolute best stack and flow for coding with AI, I suggest using V0, Bolt, Cursor, Railway, and Vercel. These are a lot of tools, and they certainly aren’t all needed, but this is my favorite workflow and in my opinion the best you can get. We already covered V0, and this is great to get your frontend started. Build the app as if you had a working backend, but you don’t. Just use placeholder information.
Once you have your frontend built, now it’s time to move to the backend. Describe the app you want to build to Bolt, but focus on the very core and basic functionality, and what you can’t get with V0. Your concern right now is to make sure you have a functional backend for your purposes. So if you need to call a certain API, then just try to get that working, no matter how the data is handled or how the app looks.
After you get that working, you can import the frontend from V0, and tell it to incorporate this with the existing backend. The frontend will generally transfer pretty well since they use TS. Try to make the prompt detailed and explain exactly where the app needs to replace placeholder data with real data. Now your task is to just make sure that you have the basic workings. Don’t worry about getting the frontend perfect, or adding tons of additional logic in the backend.
From here, a good move is to transfer this to Cursor. Now that basic infrastructure is built, Cursor is a good option to make edits and the final refinements. Cursor is cheaper than Bolt and allows you to run it locally. More importantly, you can use the GPT o1 model, which you cannot with Bolt as it’s stuck with Claude 3.5 Sonnet (although Bolt is open sourced and some have made forked versions that run locally with different LLMs). I find that GPT o1 is often in a league of its own for troubleshooting when it has the right context and prompt, and is able to fix things that no other model can.
Cursor is also better for edits because it allows you to replace code modularly, while Bolt always replaces the entire file. I feel like the latter makes it more prone to mess it up. And not only is it modular, but also gives you a preview of the changes before and after, and you have to manually accept those changes. This makes it much easier to notice when the LLM is making a stupid mistake, such as replacing an entire file with just the function that it’s changing. With Bolt, it will make the change by itself and you have to manually revert it later in case it broke the app.
Nevertheless, moving from Bolt to Cursor is optional, and you could stick with Bolt forever as long as you don’t mind the cost. I first started using more Cursor, but I ended up using Bolt more towards the end as well. Either works.
You can also get around the o1 problem while using Bolt, even though it’s less convenient. You have to get the right context to then give it separately to o1 on the GPT interface.
These aren’t all required, but this is the optimal environment to actually get the problem fixed if you’re stuck:
- Description of the app’s architecture
- Description of the app’s flow and logic
- The problem you’re trying to fix
- Error logs from Bolt
- The entire files that are relevant for the problem at hand
Your Own Backend
As I was doing full stack apps with Bolt, one thing that I quickly realized is that the backend is way more complicated than I was used to when writing Python scripts. The chance of something getting broken was way higher, and overall everything seemed more complex. If only you could have the simplicity of a simple Python script for backend and the simplicity of a simple JS website, and then you could have a working app while keeping its infrastructure and organization as simple as possible. The problem is that this is generally not feasible. First, because if you have a proper backend, that’s never going to be as simple as just uploading a single file and it’s up and running, and second, you also have to connect the frontend and the backend.
Since I had such a positive experience with Python scripts, an immediate option that came to mind was having an actual Python backend for a full stack app, and frameworks like Flask exist for this. The problem is that it’s still not easy to connect this to a frontend, you have to set up the architecture, and you can’t use existing tools like Bolt since they don’t support Python at all. Because of this, I never explored this option. Until…
I started banging my head over and over again because of React. In part just because of its complexity, but I was also getting tons of problems with some APIs and it took me a while to figure out what was wrong. Turns out that Bolt uses Netlify to deploy but as serverless functions. It’s running as WebContainers, which is highly problematic for some of the things that I was trying to build because you cannot do server-side API requests, so they kept being denied.
Eventually I decided to give Flask a try, and I had the idea that instead of making a Flask backend that the app is actually running on, maybe we just have a separate extra backend that isn’t where the app is hosted, but that can simply host some specific functions and logic we want. This would allow me to bypass the API restriction, for example. Since it wouldn’t be Bolt doing the API call, but Flask. Then I’d simply fetch the result and pass it back to Bolt.
After researching a bit on how to do this, I tried deploying a Flask backend on Railway, and I was absolutely blown away by how easy it was to set up. It’s crazy the amount of work that these platforms put in where you can deploy these with a few clicks and everything is abstracted for you. All I had to do was build the Python file on a Git repo, then import that into Railway, deploy it, and then make it publicly available. Then you just have to put your API keys as environment variables in Railway. I also created an API key for Railway itself, so that no one is able to call the Railway API without the key. And you add the Railway API to Bolt.
It’s such a simple yet powerful setup, and it’s insane that no one is talking about it in the no-code community. And this is how my Owl Review app is running. It has the normal backend built with Bolt but then calls my Flask app for some of the APIs that I was having trouble with that require server-side capabilities. And it works beautifully. Just keep in mind that for some APIs you will have to enable CORS for the API, otherwise you will give Bolt the same restriction to access your Flask backend as the actual APIs are giving Bolt.
This setup probably isn’t best practices and a subpar implementation in proper software engineering, but for these kinds of projects, I doubt that matters very much.
Lastly, I think this type of setup can be pushed even further, and I have a feeling that putting more and more of the logic in Flask is beneficial, at least all the APIs. I didn’t do it because I already had set everything up in Bolt and I didn’t want to fix something that wasn’t broken. But it seems a good idea to me to have more ownership for some of the backend logic that you can more easily fix as needed since it’s now more modular. It also has the benefit that Bolt can’t possibly mess up the logic in Flask, so easier that all Bolt has to deal with is manipulating the data coming from Flask, becoming harder to break.
And I believe you can do this while still keeping the Flask application very easy to deal with in a single file. While by default it creates an application that runs when called, you can set up different functions that run when those functions are called. Meaning that you can get closer to this idealized one-file simple backend that I first dreamed of. Not only can you make different kinds of logic for a given app, but you can make it your universal backend that works for any app you create. You can literally just add everything else you build in the future in this app, and keep everything in one place. But it’s still easy to edit as needed because if you need to create, delete, or edit something, you never have to deal with the whole application, or you can just address each function individually since they work independently. This is by far the best and simplest setup to have, and I’ve never seen anyone talk about this. Again, I’m sure this is probably stupid from a proper engineering perspective, but this is just a framework to get things to work and get started building basic MVP-like apps. As you gain experience and get more comfortable with all of this, you can build more and more complex architectures and infrastructure over time.
Practical Advice
Now let’s get into some practical advice that will save you many hours, in no particular order.
Error Logs
Probably the most useful thing you can possibly do when trying to build apps without knowing how to code is setting up error logs. You should create as many error logs as you possibly can for every single step and aspect of the flow. Even something as simple as calling an API, there are many things that can go wrong. Is the API actually being called correctly? If so, are you getting a return? What are you getting back? In what format? Was it parsed correctly? If it didn’t work, why not? Did you violate some condition of the API? Did you mess up the syntax? Did you run out of credits? Etc. Generally speaking, if you simply ask the LLM to generate error logs for a given part of the application it will do a decent job, but it’s still good for you to try to think about what errors might be helpful.
Comments
Include comments for every function of the app, and even sub-sections of a given function. While the LLM understands the code just fine, you don’t. Yet sometimes it’s very helpful to look at the code yourself, and sometimes you can notice where the LLM might be going wrong with the code if parts of it are explained in natural language. LLMs tend to do this by default when generating basic scripts, but I found that when building more complex apps in Bolt, comments are heavily neglected. Instruct the LLM to make detailed logs for everything, even if you have to do it page by page.
Backups
Create backups on Bolt often. More often than what you think you need. It’s very easy to forget to do so, and you will deeply regret it. There are two major ways to create backups on Bolt. First is to open it on StackBlitz and fork the project. This is the best because then you can open it right in Bolt again and you can continue working on it right away. The downside is that it requires more work and a few extra clicks. An alternative that I like is downloading the entire file. This is easier and you can do it with a single click, but using that backup isn’t super easy because you can’t import that into Bolt directly. You have to import it from a Git repo, meaning that you have to follow the flow we covered previously of deleting the API keys, commit to Git, importing it into StackBlitz, open it in Bolt, and putting the keys back.
Prompt Library
You will find that you will often ask the LLM the same things because they’re common parts of troubleshooting or creating something. Save those prompts so you don’t have to think or write them from scratch. For example, you might want to have a ready-made prompt that asks the LLM to explain how the architecture of the app works so you can double-check that it’s doing what you think it’s supposed to be doing. Or instructions that specify not to change the backend logic when all you want is to make some UI changes. Or extra comments to normal prompts to prevent common mistakes the LLM does, so you’re actively telling it not do that (as one example, Bolt kept wanting to change my LLM model often for some reason).
JSON
Trust me, JSON is a gift from God. Use it for everything. It will make your life 100 times easier. This is very obvious for programmers but for someone new coming in, it’s those basics that you may never learn until way later and saves you tons of headaches. Any time that you need to send, receive, or store any kind of data, you will probably want to do it in JSON. If you’re using OpenAI, use their Structured Outputs option to force a JSON response. If you using some other model, you can use Outlines by dottxt which achieves the same outcome.
Get Organized
One problem that you will find as you’re building apps is that sometimes it feels overwhelming to have everything coming from your head. As the complexity increases, it becomes harder to remember important details.
Create a Notion doc with everything about your project. I personally create pages for each major feature. First when I’m conceptualizing the logic of what that feature needs to do. And then the prompt that I’m using to make the LLM build that feature.
It’s quite helpful to save your prompts because if you have to revert to a previous version due to some bug or problem, you don’t have to re-create the prompt from scratch. This is particularly important because unfortunately chat history in Bolt is not persistent and relies on your cache.
Mock Data
When you know that the API calls are working, you don’t need to keep calling it. Create a file with mock data (either from a previous run or ask GPT to generate it), and then create a dev mode with a simple Boolean that you can easily turn on and off manually. This prevents calling the APIs over and over again as you’re testing the app and building each feature. Just make sure that the format and output is realistic. It’s also helpful if you do this earlier in development rather than trying to build it later when the app is already more complex.
Diagrams
The most important skill when trying to do something with no-code is that you need to be the higher-level brain of AI. While the AI will implement the details, you need to hold the overall flow and architecture of your app. When something breaks and the AI can’t fix it, it’s up to you to try to troubleshoot it. You probably can’t possibly troubleshoot the technical details, but you can likely figure out logically where the problem is, and that’s often all the AI needs. To do this you need to always have a perfect understanding of what your app is doing and how it works. I found that building diagrams is extremely helpful for this. For example, here is one I did for my Owl app. It has had a few updates since then, but the overall logic still holds true for the most part.
The problem with these diagrams is that there isn’t an objective level of what’s the right level of abstraction. The diagram you see above is a very oversimplified explanation of what the app does and how it works. I could easily make it three times larger, and even then many details would be missing. But that extra detail wouldn’t be useful for me in most cases. You have to try to understand what’s crucial information for the flow of the app versus irrelevant details. But generally speaking, I think that trying to take the perspective of a user going through the flow of your app, and trying to outline the basic steps required in the backend to make something happen is a good mental framework.
Another way that I like to think about it is that the right level of abstraction is when trying to describe how the app works to a friend over coffee, but that friend is technical, so he’s interested in knowing some detailed details. For instance, if I was explaining my app to a non-technical friend I’d say something along the lines that it suggests features for your product, and it searches the internet for reviews, and produces a report with AI. But for a technical friend, I may explain how that’s actually done, the APIs used, the LLM models, how the data is structured, etc.
Modularity
Make your app as modular as possible. This ensures that changes are easier to make, and it’s easier to keep track of things. When I was forced to move from my vanilla environments of HTML/CSS/JS or Python to React was completely overwhelmed and I hated that there were so many files. And it’s particularly tough when you’re used to coding through copy-pasting those files into an LLM and just have something edited or fixed. Now that you have several files, there is extra work and extra skill of knowing what files those are. Thankfully when working with Bolt or Cursor, this issue mostly disappears as it does this work for you. And very quickly I grew to appreciate this modularity and the division of files.
One problem that I frequently encounter with this, though, is that sometimes this modularity and division backfires. For example, you may fix a file that contains some logic that needed changing, but while doing so, it changes the variable or function in a way that now when another part of the app has to call it, the old way no longer works, and it has to be updated. Bolt and Cursor aren’t very good at thinking in advance for such scenarios, and from time to time you get into this annoying situation of fixing part A of the code, while breaking part B, and you get into a circle. Eventually you can figure it out, but it’s a headache when it happens and there isn’t a great solution for it.
Underestimating Complexity
Everything is way more complex than you think. If I had to predict how many hours it would take me to build this app based on its logic, I’d have guessed something like 3 to 5 hours. In reality it took me probably 30–40 hours. To be fair, a lot of that time was learning things that I won’t have to repeat, and many that you will be able to bypass completely by reading this. For example, running into countless problems with APIs, figuring out how the Flask setup works, etc. But nevertheless, it’s all part of the process.
The greater point is that even relatively basic features often take quite a long time, even though they’re very basic on paper. You have to think what to do, then you have to know how to do it, then you need to test it, and then you probably need to figure out why how you’re doing it isn’t working, or why it’s not working very well.
And there are often in-between steps that you failed to consider. For instance, I always noticed that in my app the time to generate the final report was slow, but I wasn’t too concerned about it and I just wanted to get the steps and the logic right. I figured that optimizing for speed was something simple, but it wasn’t. It actually required changing the flow considerably in some areas. To do some of these changes, I had to think and figure out some smaller in-between steps that I didn’t think of. And some of them were a pain to solve sometimes.
And sometimes I spend hours troubleshooting something or implementing a new feature, only to decide that this isn’t worth it or it’s not going to work well for some reason, so I have to backtrack to where I first started and lose all progress. For instance, I actually gave up on improving the speed of the app up to a certain point because it was such a time sink that I didn’t think it was worth it because very few people, if any, will use the app anyhow. I’d rather spend my time building something else.
When you’re thinking about an application that the logic seems relatively simple to you with, say, five steps. In reality, each step has many sub-steps, and its simplicity is based on 1) your ignorance, and 2) you assuming that you can connect all of this perfectly and it works as it should out of the box, which often does not. It’s kind of like thinking about building a car and you’re like: “Yeah simple enough, you just start by attaching the wheels to the frame, then you install the engine at the front. After that, you fit the chassis over the top and secure everything into place.” It’s not necessarily wrong but it’s oversimplistic. You will run into a million problems and there are many hidden details. Building a car is of course more complex than the typical apps you will likely try to build, but it’s just a helpful analogy.
Correct Diagnosis
Sometimes you also spend tons of time troubleshooting something that should be straightforward and easy but it’s not working, and you can’t figure out why. For example, after my app was almost finished, I wanted to add a logo through Bolt. But when I tried, it wasn’t working; the image wasn’t displaying properly. I found that super weird that it didn’t work right off the bat since it’s such a basic thing. Yet not only did it fail on the first try, but also the second, and third… and many more. I maybe spent 15–20 prompts trying to figure out why I couldn’t simply display an image. Eventually I figured out that it wasn’t my problem at all, but Bolt somehow corrupts the image when trying to upload it to its repo. When I tried to open the image on my own computer, it wouldn’t even load. Instead, I decided to display the image based on an external URL instead of hosting it myself, and I fixed the problem in 30 seconds. I spent tons of time trying to fix a ghost problem.
Another example is that part of my app involves fetching YouTube transcripts. You can’t get this from the official Google API, and thus I had to work around it. This is a small part of the app, and one that I’d have guessed is super simple to implement. Yet, it was a massive problem. I kept having a variety of issues with it, way too many to count. In the end, I realized that the API that I was using to fetch wasn’t great. And it took me way longer to realize this than it should have. I kept trying to improve things in my system that at the end of the day wasn’t I couldn’t possibly fix.
How you should always think when trying to troubleshoot is that you’re trying to falsify hypotheses. You have one problem, and that can have 20 different causes. The trick is, how can you figure it out? And this is incredibly difficult. Probably even for devs, but for non-technical people like us, it’s 10 times harder. But you just have to do your best. Keep thinking about the flow of the code, the steps involved, and the several parts that make up the system. Include as many error logs as possible, and use LLMs to try to figure out where the problem is.
Paid Tools
All the tools that I’ve recommended can be used for free. However, some are severely limited, most notably V0 and Bolt. This is unavoidable because they need to buy the tokens you’re using in the free version, so they’re quite literally losing money, and there is only so much they can use to encourage overall usage and conversion.
If you’re on a tight budget and you can’t spend any money, everything I’ve described is still doable, but much harder. Your priority should be limiting the amount of back and forth you’re doing with the AI model, and doing as much as you can in one go. The problem with this is that this is generally the opposite of what you want for optimal results, because the more actions and logic you add in a single go, the higher the chances of something going wrong. But if you have limited prompts, you don’t have much of a choice.
When troubleshooting, try to get an external model that you can get for free or cheap, rather than using the no-code platform directly. This is particularly easy with V0 because you mostly have one file you have to worry about.
The biggest problem is Bolt. First, because it has way more files, so it’s harder to get help from an external model. And second, because you run out of free credits very quickly because it’s using all the files as context, and thus its prompts are always very big and spend tons of credits.
I’d suggest trying to get the very basic backend framework working on Bolt as quickly as possible with zero care for any details, and then jumping out immediately to Cursor, and doing everything locally with a cheap model.
If you’re not on a tight budget, then I’d highly suggest just subscribing to those services, at least Bolt. Yes, it sucks adding yet another subscription, or multiple subscriptions, but if you truly enjoy this and building something, it pays off massively. It will save you tons of time and tons of headaches; it’s very worth it.
The Key Skill
Even with no-code tools and the help of LLMs, it still takes skill to build these kinds of apps. It’s certainly a different skill than coding, but it’s not completely unrelated either. A lot of learning to do this well is thinking like an engineer, not learning how to program per se, in the sense of most of what you will learn by trying to learn a language. They very often focus on syntax, specific functions, etc. The problem is that this is precisely what LLMs do almost perfectly. So in the human-AI interaction, some elements require human thought and input, and others can be somewhat automated by AI. And you’re learning mostly the latter, which is of course the opposite.
From my experience, what matters the most is thinking at a very high and abstract level and how components flow and interact together. And lastly, learning specific implementations of whatever you’re building. The specific libraries you’re using, the APIs, the hosting, etc. None of it will be taught in typical programming courses, especially beginner ones. You just have to find out what you need to use, try to use it, fail, and eventually figure it out.
Learning to Code
That said, learning how to code is still helpful. And if you’re serious about building things, even if you never see yourself as a programmer and you want to use LLMs, you should learn the basics. I’ve tried learning programming a few times in my life. I learned very basic HTML/CSS when I was a teen to edit social media pages in the era of MySpace and Hi5. I tried a couple other times later when I was an adult, but I was never able to stick with it.
If you research how to get started with coding, you will generally come up with two standard approaches. The first is learning basic frontend development with HTML, CSS, and eventually JavaScript. This is because there is a very low barrier to entry; it’s relatively simple, and you have immediate visual feedback. I’ve gone this path a few times, but ever since I started taking no-code development more seriously, I came to the conclusion this isn’t very fruitful. You will spend a lot of time learning things that you will never have to worry about in the modern world of LLMs, such as adjusting styling in CSS. From my experience, it doesn’t carry over a whole lot, and tools like V0 make frontend development incredibly powerful and good-looking with minimal effort.
The other approach is to start with Harvard CS50, which is an incredibly popular and credible resource to learn how to program starting from scratch. The problem with it is that it’s very long and fairly difficult. Many people quit in the first week, and few finish it. And to top it off, you’re learning C, which is not very practical. I’m sure it’s still helpful, but I found a similar alternative that seems to work around some of these limitations: CS50P. It’s similar to the traditional CS50 in style and structure, and also taught by the legendary David Malan. It’s shorter, easier, and you’re learning Python, which is more applicable. I’m in the middle of it right now, and it’s great. Malan is an awesome teacher, and perhaps one of the best lecturers I’ve ever seen.
I actually first thought Python wasn’t the best place to start if you wanted to mostly focus on frontend. I always viewed backend as something inherently boring and incredibly inaccessible. But I’ve changed my mind ever since starting to use these more modern tools that I’ve mentioned here. High-level thinking becomes the most important skill, and I’d say Python is much more suitable for this than something like JavaScript, even if you’re not going to implement much manually or use Python at all. I found a good setup using Flask, which is rather convenient.
I honestly still don’t think this is too effective. Even though I genuinely think it’s worth learning and I’m enjoying it so far, the amount of carryover towards actual development with LLMs is very limited, because it’s far too specific in terms of implementation. For example, knowing the syntax of a certain function. That’s not something you generally need to know. You can easily look it up or ask an LLM to explain or create it. What is helpful is knowing how the function works. What you want is understanding things at a relatively high level — for example, knowing different data types, the basic logic of conditional statements, loops, classes, etc. But rarely will you have to actually “remember” how to do it in a literal sense of how you might have needed it 20 years ago.
Coding Apps
I’ve been using an app called Mimo, which I’ve found helpful. Such apps are often a bit of a meme and viewed negatively because they don’t go very in-depth, and generally you don’t do a lot of direct programming yourself; it’s mostly multiple-choice type quizzes. But I still think it’s helpful. I initially started this as a way to improve my overall learning and ability to develop apps with no-code, but also as a way to try to reduce my quasi-addiction of Instagram reels. I was hoping to replace some quick mindless scrolling with some casual code learning. The latter didn’t work out super well because what makes Instagram so addictive and convenient for me is that I can whip it out any second and easily consume it. While Mimo has some of those characteristics, they’re not as short-form as a reel. It’s structured by lessons, and even though they’re casual and short, it still requires a solid few minutes with decent attention. To truly replace Instagram for me, I’d need something even more casual and something I can more easily tab in and out. Maybe something for me to build eventually.
Either way, I wouldn’t underestimate apps despite their sometimes bad reputation. Even if they’re not ideal, they’re better than nothing. I’ve tried to learn how to code several times during my life and never stuck with it, and this is the longest I’ve ever stuck with it so far, having a two-month streak on Mimo. And it was from Mimo that I decided to start learning a bit more properly and take Harvard CS50P. Even though the work I use it for is very little, it adds up. Just ten minutes per day eventually becomes 15 hours over three months. That won’t make you learn the basics of programming, but that’s still a massive advantage over having zero hours. Or trying the traditional CS50 and having two hours but then giving up. Things start small and you build from there. I also started with around ten minutes per day when I first started getting into reading. Over a decade later, I’ve read almost 500 books. Start small, be realistic, and build consistency.
I hope this article was helpful and saves you time when trying to build something. We’re entering a unique era and most people haven’t fully grasped it. Enjoy it.
If you want to talk about building with LLMs, feel free to reach out to me on X at @dazai0x.