While you were building, your feedback loop had a CI server. You pushed, waited ninety seconds, and got green or red. Over a year that added up to thousands of small verdicts, and each one told you whether the last hour mattered.
Then you launched, and the CI server got unplugged.
Now the work is cold emails, a Show HN, a Reddit comment, a headline tweak on the landing page. None of it returns a status code. The dashboard shows 23 daily actives today and 22 yesterday, and you catch yourself reading meaning into the extra one. For developers, that's what solo founder burnout usually looks like. It isn't overwork. It's a brain trained on fast, deterministic feedback that's suddenly running on noise.
It also shows up on a schedule. A 2024 Sifted survey found that 49% of founders say they're considering quitting. For solo builders, the exit tends to cluster four to nine months after launch. By then the ship-it high has worn off, but no metric is old enough to mean anything. Paul Graham's startup curve calls this stretch the trough of sorrow, a name that makes it sound like bad weather. I think it's closer to a missing piece of infrastructure. That's good news, because we know how to build infrastructure.
Your 23 users are statistically silent
Start by proving to yourself that the daily number is noise. Daily counts of roughly independent events behave like a Poisson process, where the variance equals the mean. So the gap between two days has a standard deviation of about the square root of their sum.
import math
def is_signal(before: int, after: int, z: float = 2.0) -> bool:
# Treat each count as Poisson: Var(after - before) = before + after
return abs(after - before) > z * math.sqrt(before + after)
print(is_signal(22, 23)) # False: diff 1, threshold ~13.4
print(is_signal(22, 40)) # True: diff 18, threshold ~15.7
print(is_signal(230, 276)) # True: a 20% lift finally clears the bar
Going from 22 to 23 is a change of about a sixth of a standard deviation. Work backwards and you need a couple hundred events per window before a 20% swing clears two standard deviations. Below that, your dashboard is a mood ring.
This matters more than it sounds. If you check DAU every morning, you're holding a daily vote on your self-worth and letting a random number generator cast it. Stop checking it. Replace it with a weekly number that adds up enough events to say something, or with the one metric that's still readable at tiny sample sizes.
Retention curves speak at small n
Growth is hard to read with 40 users. Whether those 40 users come back isn't. A retention curve that drops to zero by week four means one thing. A curve that levels off at 15% means something else, and a few dozen people per cohort is enough to tell them apart.
WITH first_seen AS (
SELECT user_id, date_trunc('week', min(created_at)) AS cohort_week
FROM events
GROUP BY user_id
),
activity AS (
SELECT DISTINCT e.user_id, f.cohort_week,
EXTRACT(DAY FROM date_trunc('week', e.created_at) - f.cohort_week)::int / 7 AS week_n
FROM events e
JOIN first_seen f USING (user_id)
)
SELECT cohort_week,
count(DISTINCT user_id) FILTER (WHERE week_n = 0) AS users,
round(100.0 * count(DISTINCT user_id) FILTER (WHERE week_n = 4)
/ NULLIF(count(DISTINCT user_id) FILTER (WHERE week_n = 0), 0), 1) AS wk4_pct
FROM activity
GROUP BY cohort_week
ORDER BY cohort_week;
Run it on Mondays and ignore it the other six days. If week-4 retention is flat or rising across your last three cohorts, the product is holding people and your problem is distribution. If it slides to zero, more cold emails won't fix it. You can stop feeling guilty about not sending them.
Pre-register your growth experiments
The cruelest part of post-launch work is that the right move and the wrong move feel the same for weeks. You can't fix the delay. What you can fix is the habit of reinterpreting the results every night at 1am.
Scientists deal with this through pre-registration: they write down the hypothesis, sample size, and failure threshold before collecting any data. You can do the same with a YAML file in your repo.
- id: cold-email-agencies-v1
started: 2026-09-01
hypothesis: "Agency owners reply to a teardown of their own onboarding flow"
metric: replies
denominator: emails_sent
min_denominator: 60
kill_if_below: 0.05
review_on: 2026-09-22
Then write a small script that won't give you an opinion until the sample is big enough:
import datetime as dt
import yaml # pip install pyyaml
def verdict(exp, counts):
n = counts[exp["denominator"]]
hits = counts[exp["metric"]]
if n < exp["min_denominator"]:
return f"NOT YET ({n}/{exp['min_denominator']}), no opinions allowed"
rate = hits / n
if rate < exp["kill_if_below"]:
return f"KILL ({rate:.1%} < {exp['kill_if_below']:.0%})"
return f"KEEP ({rate:.1%})"
with open("experiments.yaml") as f:
experiments = yaml.safe_load(f)
# Fill these from your email tool, CRM, or a spreadsheet export
observed = {
"cold-email-agencies-v1": {"emails_sent": 41, "replies": 1},
}
today = dt.date.today()
for exp in experiments:
counts = observed.get(exp["id"])
if counts is None:
print(f"{exp['id']}: no data logged")
continue
flag = " <- review overdue" if today > exp["review_on"] else ""
print(f"{exp['id']}: {verdict(exp, counts)}{flag}")
The most useful output here is "NOT YET". It turns "nobody replied, maybe the whole thing is doomed" into "41 of 60 sent, check back later." That's a pending CI job, and a pending job doesn't keep you up at night.
Commit your quit conditions before you're tired
Sunk cost takes hold when the product and your identity become the same thing. After nine months of nights and weekends, quitting feels like deleting yourself, and staying feels like the only way to justify those nine months. Either way, the most exhausted version of you is the one deciding.
So write the exit criteria while you're rested, and put them in git:
# Kill criteria: written 2026-09-15, rested, after a decent week
Review date: 2026-12-15
I stop working on this full-time if ALL of these are true on the review date:
- Week-4 retention under 10% for the last 3 cohorts
- Fewer than 3 users have ever paid anything
- No experiment in experiments.yaml hit its keep threshold
I keep going if ANY of these are true:
- One cohort levels off above 20% at week 4
- A stranger asked to pay before I asked them
The commit is the point. git log -p KILL_CRITERIA.md gives you an honest record of every time you moved the goalposts. Moving them is fine. Moving them quietly at 1am after a bad week isn't, and the diff makes that visible. Oddly, having explicit conditions for quitting is what lets most people keep going. Every day that doesn't trip a condition is a day you've already decided to continue.
Add a code reviewer to the business
When you were building, you had linters, type checkers, maybe a friend reviewing PRs. After launch, the only reviewer left is the voice in your head, and it isn't a fair one.
Put a recurring outside review on the calendar: 20 minutes every two weeks with one person who isn't on the project. Show them the retention output and the experiments file, not the pitch. Another solo founder is ideal, since they won't be polite and they already know the numbers are small. You're not really there for advice. You're there so someone else reads the same data and your interpretation isn't the only one in the room.
The Monday script
Put it all behind one command you run each week:
#!/usr/bin/env bash
set -euo pipefail
psql "$DATABASE_URL" -f queries/retention.sql
python scripts/experiments.py
git log --oneline -- KILL_CRITERIA.md | head -5
It gives you three answers: are people staying, which bets have enough data to judge, and have you been quietly rewriting your exit terms. That's the CI server you lost at launch. It's slower, it runs weekly instead of on every commit, and it'll say "not yet" far more often than you'd like. But a pending build feels very different from silence, and most of the quitting in that four-to-nine-month window happens in the silence.
What metric do you check every day that probably can't tell you anything at your current sample size?
Originally published at https://robatdasorvi.com/stories/why-most-solo-founders-give-up-at-the-same-place-in-the-product-journey
Top comments (0)