Most AI side projects die before seeing a single user. I know because I've killed plenty of them myself. The pattern was always the same: I'd get excited about some idea, spend two weeks building a "robust" backend, obsess over the perfect prompt, and then lose interest before ever putting it in front of a real person.
So this year I decided to do the opposite. I forced myself to ship three AI-powered MVPs in two months — not because I had a grand strategy, but because I wanted to break the cycle. Here's what I learned, what I'd do differently, and why shipping "ugly" still beats building "perfect."
The three projects, and what they taught me
The first was a tool that turns meeting transcripts into action items. The second was a CLI that generates commit messages from git diff. The third was a simple chat-based interface for querying my own notes.
None of them are revolutionary. None of them will make me rich. But all three got real users (including people who aren't me), and all three taught me something about where AI projects actually fail.
The biggest lie: "I need to host my own model"
When I started, my instinct was to self-host everything. I read blog posts about running Llama 3 on a GPU, about quantization, about vLLM and llama.cpp. I even bought a used RTX 3090 on eBay. I spent a full weekend getting a model to respond to "Hello" without crashing.
Then I did the math.
That GPU cost me $600. It draws about 350 watts under load. My electricity rate is roughly $0.15/kWh, so every hour of inference costs around a nickel — before accounting for the fact that I'd need to maintain the thing, update dependencies, and handle the inevitable memory leaks.
Meanwhile, a decent hosted API costs me maybe $0.0002 per request for the kind of small tasks I was doing. If I processed 10,000 requests a month, that's $2. With self-hosting, I was paying $600 plus hours of my life for the privilege of worse latency and constant maintenance.
The decision was obvious: use managed APIs. I don't care about "owning my infrastructure." I care about shipping.
Lesson 1: Scope to a single painful task
The first project (transcript → action items) almost died because I kept adding features. "Let's also summarize the transcript. Let's detect sentiment. Let's generate follow-up emails." By day three, I had a beautiful but useless app that did everything poorly.
I deleted half the code, kept one feature — extract action items with who owns them — and shipped that. It took me one more day. That version got used.
The lesson: your AI side project doesn't need to be impressive. It needs to solve one specific problem better than copy-pasting a prompt into ChatGPT. For me, that was "paste a transcript, get a list of tasks with owners." That's it.
Lesson 2: Use the simplest API wrapper you can get away with
For the CLI commit message generator, I initially built a wrapper around the OpenAI SDK. It worked, but I found myself tweaking parameters, adding retry logic, and handling edge cases for streaming responses. Overkill.
Then I rewrote it as a single function using fetch. Here's the core of it:
async function generateCommitMessage(diff) {
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.OPENAI_API_KEY}`,
},
body: JSON.stringify({
model: "gpt-4o-mini",
messages: [
{
role: "system",
content:
"You are a senior developer. Write a concise conventional commit message based on the diff. Max 50 characters.",
},
{ role: "user", content: `Diff:\n${diff}` },
],
}),
});
const data = await response.json();
return data.choices[0].message.content.trim();
}
That's the whole integration. No SDK, no streaming, no retries. If the API fails, I just print an error and let the user run git commit manually. It's not fancy, but it ships.
What surprised me was how much faster this made development. I stopped thinking about "AI plumbing" and started thinking about the actual problem: parsing the diff, filtering out binary files, and handling edge cases like empty commits. The AI part was just a function call.
Lesson 3: Ship before you feel ready
I have a bad habit of refactoring before launching. With the note-querying app, I caught myself rewriting the same function three times because I was "sure" I'd need to scale it. I didn't. I needed to get it in front of a friend who had a pile of unread notes.
So I set a hard deadline: 48 hours from start to deployment. I used a simple Express server, a single HTML page, and the same fetch pattern from above. I deployed it on a $5 VPS. It was ugly. The UI was a textarea and a button. But it worked.
Two things happened after shipping.
First, the feedback loop finally started. My friend said, "It's nice, but I want to upload PDFs, not just paste text." That's the kind of insight you can't get from staring at your own code. It took me four hours to add PDF support using a basic parser. In two days, the app was genuinely more useful than it had been after two weeks of "perfecting" the backend.
Second, I stopped caring about the "quality" of my AI integration. No one asked me what model I was using. No one asked about temperature or top-p. They asked, "Can it find the note about my landlord's email?" That's the only metric that matters.
The real cost of building with AI
Let's get specific about numbers, because I think we overestimate how much an AI side project costs.
For all three MVPs combined, my API spend over the two months was $14.83. That's including the inevitable "test runs" where I fed the same prompt in a loop while debugging. The biggest single expense was the commit message generator, because I accidentally left a debug script running overnight. That cost $3.20. Still cheap.
The real cost was my own time. And the biggest time sink wasn't the AI part — it was everything around it: auth, deployment, CSS, handling edge cases. Once I accepted that AI is just a small piece of the puzzle, I stopped treating it like the hard part.
What I'd tell my past self
If I could go back, I'd give myself three rules:
- Use a hosted API. Don't even think about self-hosting until you have paying users.
- Write the worst possible version of your app that still does the job. Then ship it.
- Find one person who wants the thing and get it in their hands by the end of the week.
That last one is the hardest. It's tempting to keep polishing, to add one more feature, to try a better prompt. But the only way to know if an AI side project is worth building is to let someone use it. And they can't use it if it's still in your local repo.
By the way, about infrastructure
Since I switched to managed APIs, I've been using a pay-as-you-go endpoint that aggregates multiple providers under one key. It's been useful for two reasons: I don't have to create accounts at four different AI companies, and when one provider's API has an outage, I can switch models with a one-line config change.
I'm not going to pretend it's the only option. But if you're building a side project and don't want to deal with billing per provider or managing multiple keys, it's worth a look. The one I use is tai.shadie-oneapi.com — it's an OpenAI-compatible gateway, so the code I showed above works with a simple base URL swap.
There's no lock-in, which is the best part. If it stops working tomorrow, I can switch back to the official API and my code doesn't change. That's the kind of infrastructure decision I've learned to make: reversible, cheap, and boring.
Shipping is a skill
After two months and three MVPs, the biggest thing I learned is that "shipping" is not a personality trait. It's a skill you practice. And AI side projects are a great way to practice, because the cost of failure is tiny — a few dollars and a few evenings.
The next time you have an idea, don't build the platform. Don't design the architecture. Don't research the perfect model. Write a single function, wrap it in the ugliest UI you can tolerate, and put it in front of a human.
The first version will embarrass you. That's fine. You can fix it later — if anyone actually cares.
Top comments (0)