Building a micro-SaaS in an afternoon with AI
How I used v0 and Cursor to ship a functional SaaS in just a few hours
I already shared how I used Cursor to ship an iPhone app I use every day, but I’ve been itching to actually go 0 to shipped with a web app using only AI tools.
In today’s post, I’ll share how I actually did this! It’s worth noting that while I’m a software engineer, I work mostly in backend with Ruby and Python. I’m going to make this project in Next.js to stretch my skills a bit.
If you want to go ahead and use the app, check it out!
Now read on to see how I prototyped this with v0, added features with Cursor, and got myself into a huge mess by blindly accepting output in a framework I’m not skilled in.
The idea for my micro-SaaS
I’m not quiet about the fact that my favorite productivity tool is a 25 minute timer. I’ve used various apps for this, mostly pomodoro apps, but I find myself reaching for something simpler in the last year. These days, I just google “25 minute timer” and that’s it.
Still, I’ve been thinking it would be really nice to have this in a tiny web app that also shows a history of my work sessions. So that’s the idea for Deep Work Timer!
Starting with Vercel’s v0
First I started with Vercel’s v0, since I hear it’s really good for prototyping apps (especially Next.js apps).
The first result was pretty much what I was after. I want more features, but I prefer to use Cursor to go further. So I synced this project to GitHub and then cloned the project locally.
Now we’re only about 5 minutes in and I have a working prototype running on localhost!
Using Cursor to make my first change
The only really important thing I want next is the option to add a note to each session about what I did.
You probably already know I’m obsessed with Cursor, so it should be no surprise it’s the next tool I reached for.
So I opened the project in Cursor and started a new chat in Agent mode with this prompt:
When the timer finishes the app logs a work session. Make an optional field in the list of work sessions for each session for the user to optionally add a note about what they worked on. Make it look really nice and when possible use the components we already have.
I was surprised how fast the agent completed this, and it worked almost perfectly in one shot!
You probably notice that there’s two identical entries for the session, which is an interesting bug. No big deal, I just set the agent out on a task to fix that bug:
It would also be nice if I could type what I’m working on before I set the timer, so we’ll add that next. I opened a new chat session (as you should for every new feature) and started with this prompt:
Right now, the user can only add what they worked on into a session entry after it ends. Add a field to the timer for the user to optionally put what they're working on and when the timer expires, that will show in the field that they would otherwise add it to.
The agent made a couple of small changes and then I verified that it works:
Putting it on the web
This is pretty much MVP to me - this completely replaces the “set 25 minute timer” Google search I was doing and adds the work session history. There’s a few things I want to add (like user accounts) but let’s get this on the web first.
First, I set the meta title and meta description for the app so it’s no longer v0 defaults.
Then, I registered deepfocustimer.com 🎉
Vercel had actually already set up automatic deployments for the app (shoutout v0), so all I had to do was push my commits and set up the domain configuration.
Using Supabase to add user accounts
Now that the MVP is on the web, I actually want to make it possible for users to register an account, start a subscription, and have a persistent work session history.
Here’s how I kicked this off:
This made a huge number of changes and then prompted me with instructions to setup a Supabase account, run the schema generation it created, and link my local environment to Supabase with environment variables.
I usually roll my own authentication with Rails so this was shockingly fast.
While I was doing this, I went ahead and made some design changes to. What do you think?
Using Stripe to charge users
To wrap this up I’d like to charge signed in users a subscription fee. I want users to be able to use the timer for free and see recent sessions, but if they pay and create an account they can see persistent work session history (and later other features).
This actually took the most time to implement out of anything. I won’t share a ton of details since payment implementation is somewhat sensitive, but know that you should put care into this and not blindly accept output from your LLM.
This part took many multiples of the time the rest of the app. In fact, my lack of understanding of what was actually being built as I went along was a key factor in why this took so long. Adding payments and webhooks revealed a number of problems with the rest of the app that had to be fixed.
This really reinforces to me a key belief I have formulated about working with AI:
AI tools, no matter how clever, should never take the place of a firm understanding of what you’re building.
Keep this in mind when you’re leaning on AI tools. Just prompting and accepting the output might be fun for a silly side project, but serious work requires serious thought.
So where’s the moat?
Some folks are being pretty loud about low-cost software removing the moat that a lot of SaaS has. I’m somewhat on board with this, but not entirely. Not everyone wants to build everything themselves from scratch, even with an LLM supporting them. I build stuff like this because I like to build stuff - not everyone has that bug.
So maybe the moat is ambition? Distribution? I’m not sure. It makes me cautious to sink a lot of effort into software knowing that the barrier to entry is much lower. Still, I wanted a tool for timing and logging my work and know I have it. It works exactly like I want it to and I hope some other folks get use out of it too!
And honestly, this was a lot of work. The recap I give here isn’t comprehensive, I spent forever digging through Vercel, Supabase, and Stripe logs trying to figure things out. I don’t expect everyone on earth to be pumped about that.