Production readiness for solo founders: a 9-point checklist
No fluff, no philosophy — just the items that, when missing from an AI-built MVP, break in production. Nine of them. Each one fixable in an afternoon.
You shipped an MVP with Cursor / Lovable / Bolt / Claude Code. The demo works. The first paying customer is two days away. Here is the minimum viable hardening list before they hit it.
I have ordered these by "what blows up first in production." Do them top to bottom. Each item has a "good enough for now" version — the cheapest thing that actually closes the gap. You can do all nine in a single weekend.
1. Get secrets out of git
Time: 30 minutes. Tool: any text editor, plus a fresh API key from each provider.
- Add to
.gitignore:.env,.env.local,.env.production,.env.*(with an explicit!.env.example). - Run
git rm --cached .env*to untrack any that are already in the repo. - If you ever pushed a real key — rotate it. Treat it as compromised. It is.
- Create
.env.examplewith every variable name and a comment, no values. Future-you will thank you.
Why this is item one: every other item on the list assumes you do not have a Stripe live key in the public history of your repo.
2. Set up error tracking
Time: 20 minutes. Tool: Sentry's free tier (or Bugsnag, or Highlight).
- Sign up for Sentry, create a project for your stack.
- Install the SDK (
@sentry/nodeor@sentry/reactor@sentry/nextjs). - One initialization line at app startup. Done.
You now find out about every uncaught exception, with stack trace and request context, the moment it happens. Without this, your first "the site is broken" notification is a customer email — and by then it has been broken for hours.
// example: Express
import * as Sentry from '@sentry/node';
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 0.1, // 10% transactions sampled
environment: process.env.NODE_ENV,
});
3. Add CI that runs on every PR
Time: 30 minutes. Tool: GitHub Actions (free for public repos, generous free tier for private).
Drop this in .github/workflows/ci.yml:
name: CI
on:
pull_request:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run lint --if-present
- run: npm run typecheck --if-present
- run: npm test --if-present
- run: npm run build --if-present
Now every PR runs your linter, typechecker, tests, and a build. The day you accidentally introduce a type error, GitHub stops you from merging it. This is the cheapest possible safety net.
4. Add at least one health-check endpoint
Time: 5 minutes.
You need a URL that returns 200 OK when your app is alive. Your hosting provider, your monitoring service, and your future load balancer will all want this.
app.get('/health', (_, res) => res.json({ ok: true, ts: Date.now() }));
Then point an uptime monitor at it. UptimeRobot and Better Stack both have free tiers. You will know within 60 seconds when your app goes down. Without this, you find out when a customer Twitter-DMs you.
5. Rate-limit anything public
Time: 15 minutes.
Any endpoint that calls a paid third-party (OpenAI, Stripe, Twilio, SendGrid) needs a rate limit. Any signup or login endpoint needs one too.
import rateLimit from 'express-rate-limit';
app.use('/api/ai', rateLimit({
windowMs: 60 * 60 * 1000, // 1 hour
max: 30, // 30 requests per hour per IP
standardHeaders: true,
legacyHeaders: false,
}));
app.use('/api/auth', rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // 5 attempts
}));
Tighten as needed. The default of "no limit" is how indie hackers wake up to $4,000 OpenAI bills.
6. Pin and audit your dependencies
Time: 20 minutes (one time) + 5 minutes / week (ongoing).
- Make sure your
package-lock.json/pnpm-lock.yaml/yarn.lockis committed. - Run
npm auditright now. Fix anything high or critical that has a patch. - Enable Dependabot on the repo. It will open PRs automatically when patches drop.
- Add to your CI:
npm audit --audit-level=highas a build step. Fail the build on new highs.
For Python use pip-audit; for Go, govulncheck; for any language, the OSV.dev API works.
7. Add structured logging
Time: 30 minutes.
console.log is fine for dev. In production you want JSON logs that your hosting provider's log viewer can search.
import pino from 'pino';
export const log = pino({
level: process.env.LOG_LEVEL || 'info',
redact: ['req.headers.authorization', 'password', 'token', 'apiKey'],
});
// usage
log.info({ userId, route: '/api/scan' }, 'scan request');
log.error({ err, userId }, 'scan failed');
The redact config matters. Without it, your logs leak any header or body field that contains a secret. With it, those fields are replaced with [REDACTED] automatically.
8. Set security headers
Time: 5 minutes.
import helmet from 'helmet';
app.use(helmet());
Or in Next.js, configure in next.config.js headers. Test what you got at securityheaders.com — aim for an A. The defaults are sensible; tune only the Content-Security-Policy if you load third-party scripts.
9. Take a backup of production data
Time: 30 minutes (depending on database).
If you are on Supabase, Neon, Railway, or Render, automated backups are usually a checkbox in the dashboard. Turn them on. Set retention to at least 7 days.
If you are running your own Postgres, set up a daily pg_dump to S3 / R2 / B2 with a one-line cron. Test the restore at least once.
You will thank yourself the first time a migration goes wrong, or a customer asks "can you restore my data from yesterday?" The answer "no" is unacceptable; the answer "yes, give me 30 minutes" is what makes you a real business.
What is not on this list
Notice what is missing: Kubernetes, microservices, multi-region anything, dedicated SRE tooling, fancy observability stacks. None of that matters at this stage. You need the nine items above, in that order. Anything beyond is premature.
Also missing: 100% test coverage. You do not need it. You need the CI pipeline (item 3) plus tests for the two or three flows that, if broken, sink your business. The auth flow. The payment flow. Maybe the core "happy path" of your product. Test those, skip the rest until they hurt.
How to know what to do first for your repo
This is a generic checklist. Your repo has a specific gap pattern. Run a free CodeClanker scan and you will get a prioritized list ordered by what would fail first in your specific codebase — including which CVEs are in your dependencies, which secrets you committed, and which dimension is your weakest.
Want a personalized version of this list?
Free scan, prioritized findings for your specific repo.
Run a free scan →