CLAUDE LABJP
PRICING — September 1 was the scheduled date for the Sonnet 5 price increase, and it did not happen. The introductory $2/$10 per MTok now stands as the regular pricePARTNER — Salesforce and Anthropic announced Claudeforce, an expanded partnership. The Salesforce in Claude plugin ships with 37 prebuilt sales skills, from meeting prep to pipeline managementTRUST — Claudeforce serves Claude through Amazon Bedrock inside the Salesforce Trust Boundary, so data and inference never leave the security perimeter — an answer aimed squarely at regulated industriesBETA — Salesforce in Claude is with select pilot customers for now, with an open beta expected during SeptemberLIMITS — The 50% weekly-limit boost runs through September 13. From September 14 the permanent level is 25% above the pre-promotion baseline, roughly a 17% cut from todayRELEASE — Claude Code has shipped nothing since v2.1.251 on August 28. Against a pace of one release every 0.8 days, a four-day gap is among the longest yetPRICING — September 1 was the scheduled date for the Sonnet 5 price increase, and it did not happen. The introductory $2/$10 per MTok now stands as the regular pricePARTNER — Salesforce and Anthropic announced Claudeforce, an expanded partnership. The Salesforce in Claude plugin ships with 37 prebuilt sales skills, from meeting prep to pipeline managementTRUST — Claudeforce serves Claude through Amazon Bedrock inside the Salesforce Trust Boundary, so data and inference never leave the security perimeter — an answer aimed squarely at regulated industriesBETA — Salesforce in Claude is with select pilot customers for now, with an open beta expected during SeptemberLIMITS — The 50% weekly-limit boost runs through September 13. From September 14 the permanent level is 25% above the pre-promotion baseline, roughly a 17% cut from todayRELEASE — Claude Code has shipped nothing since v2.1.251 on August 28. Against a pace of one release every 0.8 days, a four-day gap is among the longest yet
Articles/Claude Code
Claude Code/2026-05-06Advanced

90 Days Building a Solo SaaS with Claude Code — And the Three Things I Got Wrong

A working log from 90 days of building a solo SaaS with Claude Code — design conversations, model routing, and Cloudflare Workers constraints. Revisited months later against primary docs, with three technical claims corrected in place.

claude-code131saas2indie-dev14monetization21next.jsstripe6

Build a SaaS solo, and make more from it than you spend on Claude Code. That was the entire goal. I kept a running log for 90 days starting in February 2026, and this article is that log made public.

This isn't a success story polished for social media. It includes the wrong turns, the bad calls, and the tokens I burned for nothing — because those parts are where you'll find the most useful signal.

There's one more thing. Months after publishing, I went back through every technical claim in this article and checked it against the Cloudflare and Claude Code docs. Three of them were wrong. Not the docs — me. I've left the original claims in place rather than quietly editing them, with a correction next to each one. A wrong belief you can see being corrected is more useful than a clean paragraph that never shows its work.

1. Why Claude Code?

"Why not Cursor?" is the first thing people ask. I asked it too, for a while.

What changed my mind was a bug fix session. Claude Code traced the impact across multiple files, rewrote the tests, and staged a commit — autonomously, without me orchestrating each step. Cursor excels at in-editor completion, but Claude Code thinks through work. For SaaS development where dependencies get tangled fast, that difference is meaningful.

The other reason was cost transparency. Claude Code runs on Anthropic API usage billing, so I always knew exactly what I was spending and why. Flat-rate tools obscure that feedback loop. As an indie developer, cost awareness is directly tied to profit margin.

2. Choosing the Product (Day 1–7)

The first week went entirely to product selection. I used three filters.

① Something I'd use every day
The most reliable demand signal is whether you personally need it. I picked a unified dashboard for managing sales, reviews, and rankings across multiple App Store products.

② A stack where Claude Code excels
Next.js + TypeScript + Stripe + Cloudflare Workers. I chose this because Claude Code is deeply familiar with it — error self-correction rates are high, and generated code rarely needs major rework. If I'd gone with Ruby on Rails or Django, the learning cost and debugging overhead would have compounded.

③ Monetizable complexity within three months
I designed for "small start, charge early." The plan wasn't to finish and then add billing — it was to ship the first paid feature on Day 30 and work backward from there.

3. MVP Design — A Week of Architecture Conversations (Day 8–14)

Before writing a line of code, I spent a week working through the design with Claude Code, leaning heavily on plan mode.

# Example from the design phase
claude --model claude-opus-4-6 "
Review this architecture for Next.js + Cloudflare Workers.
 
Requirements:
- Fetch data from App Store Connect API
- Unified dashboard for sales and reviews across multiple apps
- Stripe Pro monthly subscription ($5/month)
- Must scale to 10,000 users
 
Known constraints:
- App Store Connect API has rate limits
- Cloudflare Workers CPU time budget (10 ms per request on the Free plan)
"

Two architectural pitfalls surfaced from that conversation.

Correction 1 (2026-08-31)
That prompt above carries a claim I repeated for months: "Cloudflare Workers CPU limit is 10ms per request." That figure only describes the Free plan.

CPU timeWorkers FreeWorkers Paid
Per HTTP request10 ms30 seconds by default, raisable to 5 minutes
Per Cron Trigger10 ms30 seconds (interval under 1 hour) / 15 minutes (1 hour or more)

The part that actually mattered, and that I had backwards: time spent waiting on fetch(), KV reads, or database queries does not count toward CPU time (Limits). So my worry — "we call several external APIs per request, we'll blow the CPU budget" — was aimed at the wrong thing. What burns CPU is walking the JSON you got back and aggregating it in JavaScript.

Raising the ceiling on the Paid plan is a single config block:

{
  "limits": {
    "cpu_ms": 300000 // default is 30000 (30 seconds)
  }
}

Was the Cron + KV offload wasted, then? No. Ten milliseconds is genuinely tight — Cloudflare's own guidance notes that workloads doing auth, server-side rendering, or large payload parsing typically land in the 10–20 ms range. Precomputing the aggregation was the right call. I just held the right conclusion for the wrong reason, which is a fragile place to be.

Pitfall 1: Cloudflare Workers CPU limits
Aggregating App Store Connect data inside the Worker would exceed the CPU budget. Claude Code's recommendation: offload aggregation to a Cron Trigger and write results to KV. Making that call on Day 8 prevented a painful refactor later.

Pitfall 2: Stripe Webhook idempotency
A naive "charge complete → set KV flag" design breaks under Webhook retries. Claude Code flagged this before I'd even thought about it. Building idempotency keys into the design from the start avoided a class of bugs I've been burned by before.

4. Implementation — Model Switching and Token Discipline (Day 15–60)

This is the phase with the most direct impact on cost. Here's the decision framework I settled on.

Model assignment by task type

TaskModelReason
Architecture / design decisionsclaude-opus-4-6Requires complex reasoning
Feature implementationclaude-sonnet-4-6Best cost-to-quality ratio
Simple refactorsclaude-haiku-4-5Fast, cheap
Bug fixes with known root causeclaude-haiku-4-5Direction already set

The IDs above — claude-opus-4-6, claude-sonnet-4-6, claude-haiku-4-5 — are what I actually ran during those 90 days. They're still valid IDs, though Opus 5 and Sonnet 5 have since shipped. The generation moved; the shape of the routing didn't. Reasoning to the top tier, drafting to the middle, mechanical edits to the bottom. Substitute the current names and the table still holds.

In practice, I used Opus only for the morning design session. Everything else went to Sonnet and Haiku. My invoice dropped noticeably starting that month. I originally wrote "roughly 40%" here, and I've cut that number: I changed two things at once — model routing and shorter sessions — and never isolated them. One of the two may have done nothing.

Session discipline

The most common Claude Code mistake I see — and made myself — is letting sessions run too long. When context bloats:

  • The model starts proposing implementations that contradict earlier decisions
  • Correction loops multiply, burning tokens
  • It loses the thread of what changed and why

My fix was CLAUDE.md as a state ledger. At the end of each session, I wrote down what was decided. At the start of the next session, I loaded it in first.

<!-- CLAUDE.md state section example -->
## Current Implementation State (2026-03-15)
 
### Completed
- App Store Connect API wrapper (src/lib/asc.ts)
- Cloudflare KV caching strategy (5-minute TTL)
- Stripe Webhook idempotency key implementation
 
### Next session tasks
- Build dashboard UI components
- Add recharts for data visualization
- [ ] WARNING: recharts does not work in Cloudflare Workers (SSR is disabled)

The warning notes are the most important part. Claude Code doesn't remember the last session, but the document does.

5. First Paying Customer (Day 30)

The first paid feature shipped on schedule. One design decision is worth sharing.

Reducing friction from free to paid

Claude Code's initial proposal for the onboarding flow asked for payment info immediately after signup. I pushed back and rewired it:

Sign up → 7-day full access trial → Day 8: paid features gated → Stripe Checkout

My reasoning was personal: services that ask for a card before I've seen any value lose me immediately. Let users experience the product first.

I'd like to report what happened to conversion. I can't, honestly. At Day 30 the denominator was under a hundred sessions, and "12% to 27%" at that sample size is a wish wearing a percentage sign. It was in the original draft; I've removed it. If you want to measure this properly, wait for a few hundred sessions per arm before you believe the delta.

The Stripe implementation was a one-line config change. The harder part was designing the email sequence — when to remind users the trial is ending, how to frame the ask — and that's where my back-and-forth with Claude Code was most iterative.

6. Production on Cloudflare (Day 60–90)

Three errors in production required Claude Code's help to diagnose. All were Cloudflare Workers-specific.

Error 1: Cannot perform I/O on behalf of a different request

claude "Analyze this stack trace from a Cloudflare Workers environment.
[paste stack trace]
 
I believe this is triggered when a KV operation is called from 
a context that has already resolved. What's the fix?"

The answer came back instantly, and I recorded it as: root cause was a KV write without waitUntil(). Fix: five lines.

Correction 2 (2026-08-31)
That's the wrong root cause. This error fires when an I/O object created in one request's context — a response body, a stream, an in-flight binding operation — is touched from a different request's handler. The usual way to cause it is stashing request-scoped state in a module-level variable. Isolates are reused across requests, so the next request reaches for the previous request's belongings and the runtime stops it. The fix is to keep per-request values out of global scope entirely and pass them through arguments or env bindings (Workers Best Practices).

waitUntil() solves a different problem: continuing work after the response has been sent. It extends execution for up to 30 seconds past the response or the client disconnect. My code had both defects at once, and adding waitUntil() made the symptom disappear — which I mistook for having found the cause. Those are not the same thing, and the difference cost me a rewrite months later.

Error 2: deploys started failing on Worker bundle size

This one came from the content-serving Worker I was maintaining alongside the dashboard, not from the dashboard itself. Content lived in one large JSON file bundled into the Worker, and past a certain record count the deploy stopped going through.

Claude Code proposed separating metadata from HTML content, writing the content out as individual static asset files and fetching them at runtime through the ASSETS binding. Having the reasoning explained alongside the generated code made a structural change feel manageable.

Correction 3 (2026-08-31)
I titled this "62 MiB Worker bundle limit" and called it a "traversal limit." Neither is right. There is no 62 MiB limit and no such thing as a traversal limit. The real numbers:

Worker sizeWorkers FreeWorkers Paid
After gzip compression3 MB10 MB
Before compression64 MB64 MB

The 62 I was carrying around was a half-remembered 64 — the uncompressed ceiling — while the number that actually stops your deploy is the compressed one. You can check yours without deploying:

wrangler deploy --outdir bundled/ --dry-run
# Total Upload: 259.61 KiB / gzip: 47.23 KiB

When that gzip: figure starts approaching 3 MB (or 10 MB on Paid), it's time to move config files, static data, and binary blobs out of the bundle and into KV, R2, or static assets.

90-day cost and revenue snapshot

ItemAmount
Claude Code token cost (90 days)~$300
Cloudflare Workers (free plan)$0
Stripe feesVariable, scales with revenue
MRR at Day 90Not disclosed

Token cost was heaviest in month one — about $130 — before I tightened the model-switching rules and CLAUDE.md discipline. Months two and three averaged around $85 each. Those are invoice figures, not estimates. What I can't tell you is which change did the work, because I made both in the same week. If you want the answer, introduce one at a time and read the invoice a month later. I didn't, and now I can only report the total.

I keep MRR private not to be coy, but because a number from a project this size sets an expectation that doesn't transfer. Different product, different audience, different order of magnitude.

7. What the 90 Days Actually Taught Me

What worked

Spending real time on design. The two-week architecture phase with Claude Code meant the implementation phase had almost no major course corrections. I never had to tear out a foundational decision.

Documenting failures in CLAUDE.md. Writing down what went wrong between sessions meant I didn't repeat mistakes. Claude Code doesn't have memory across sessions — but the project document does.

What I'd do differently

Less perfectionism on UI. The first paying customers cared about whether the tool solved their problem, not whether the dashboard looked polished. I burned probably ten days on UI detail that didn't move conversion.

Shorter sessions. I once ran an eight-hour session that ended with Claude Code generating code that contradicted designs it had made four hours earlier. I rolled everything back. Now I break at two hours and update CLAUDE.md before stopping.


Ninety days is enough time to find out whether you can build a SaaS — and whether you can get someone to pay for it. Claude Code compressed the implementation timeline meaningfully. But "what to build" and "when to cut your losses" remain human decisions.

Ninety days was enough to answer "can I build this at all." Getting to revenue wasn't Claude Code alone — years of shipping small products taught me when to stop polishing. I originally claimed it made me three to five times faster. I've cut that too. I never measured it, and a multiplier I can't reproduce isn't worth the credibility it borrows.

Rewriting this piece taught me something the original 90 days didn't: the answers that arrive instantly are the ones most worth checking against a primary source. All three corrections above trace back not to Claude Code being wrong, but to me compressing its answer into a shorter, more confident sentence than the evidence supported. A symptom disappearing is not the same as a cause being understood.

If you want to try this yourself, start with a 30-day challenge: get one person to pay you for something before the month ends. That constraint sorts your priorities for you. And when you write it up, put the doc URL next to every technical assertion while you still remember why you believed it. Your future self will thank you. Mine spent half a day reconstructing three of them.

Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $15 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Claude Code2026-04-28
Weekend MVP with Claude Code — From Zero to First Revenue in 48 Hours
Build a minimum viable product in a single weekend using Claude Code, integrate Stripe payments, and get your first paying customer — with actual prompts and commands shown step by step.
Claude Code2026-06-02
Two Weeks of Splitting iOS Work Between Claude on Xcode and Claude Code
I ran Claude on Xcode, which lives in the Xcode sidebar, alongside Claude Code in the terminal across two weeks of real wallpaper-app work. Here is how I ended up dividing the tasks, and the simple rule I use to decide which one to open.
Claude Code2026-05-27
11 Days in Crashlytics: A Claude Code Debug Loop Across Two Android Wallpaper Apps
After shipping Beautiful Wallpapers v2.0.0 and Ukiyo-e Wallpapers v1.7.0 in early May, Crashlytics and Play Console threw more than 30 new issues at me in 11 days. This is the operations log of how I drove the fix list down to v2.1.1 / v1.8.1 using Claude Code as a triage partner.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →