You Think It's Ready. Is It?
You've built the thing. It works on your machine, it works in staging, you've shown it to a few people and they didn't break it. You're ready to ship — or maybe you already have.
Here's the uncomfortable question: ready by whose standard?
“It works” and “it's production ready” aren't the same thing. Production means real users doing unexpected things, bots probing your endpoints, traffic spikes at inconvenient hours, and your Stripe webhook firing at 2am when you're asleep. A project that survives your test cases is not the same as a project that survives the internet.
This checklist is for indie hackers and solo founders who are either about to flip the switch or have already flipped it and are quietly hoping nothing breaks. Work through it honestly. The goal isn't to scare you — it's to give you a clear-eyed view of what's actually in place before your users find out what isn't.
The Checklist
Security
This is the one that bites people hardest, and it's the category where “it works” is most dangerously misleading. A broken form is embarrassing. A security hole is a breach disclosure email to your users.
- No secrets in your code or git history. API keys, database URLs, Stripe keys — none of these should be in your codebase, and you should check your git history too, not just the current state of the files. Run a scan at gitdoctor.io before you make anything public.
- Auth checks on every protected route.If a user has to be logged in to see it, verify the session server-side on every request. Not just client-side. Not just “mostly.”
- Users can only access their own data. Row-level checks, not just “are you logged in.” User A should not be able to fetch User B's data by changing an ID in a URL.
- Rate limiting on sensitive endpoints.Login, password reset, signup, anything that triggers an email or SMS — all of these need rate limiting. Otherwise you're one script away from a surprise bill and a locked-out user base.
- Input validation and sanitization. Validate on the server. Never trust what comes in from the client, even if you also validate client-side.
- HTTPS everywhere.No exceptions. Most hosting platforms handle this for you — make sure it's actually on.
Reliability
Reliability is what separates a demo from a product. Things will go wrong. The question is whether you'll know about it, and whether your users will hit a cryptic error or something that handles gracefully.
- Error boundaries and fallback UI. Unhandled promise rejections and uncaught exceptions that bubble up to users as blank screens or cryptic JSON errors are not acceptable in production. Handle failures where they can happen.
- Logging that actually tells you what happened.
console.logdoesn't count. You need structured logs you can query — Logtail, Axiom, Datadog, whatever fits your stack. When something breaks, you need to know what happened without SSH-ing into a server. - Uptime monitoring.Something should be pinging your app every few minutes and alerting you when it goes down. Better Uptime, UptimeRobot, and similar tools are free to start. There's no excuse to find out your site is down from a user DM.
- Graceful degradation for third-party failures. If your email provider is down, your AI API is slow, or your payment processor returns an error, does your app fail gracefully or does it explode?
- Database connection limits.If you're using a serverless function with a traditional database, connection pooling is not optional. PgBouncer, Prisma Accelerate, or your hosting platform's proxy — pick one.
Performance
Performance is an SEO signal, a conversion factor, and a first impression. A slow app that works correctly still loses users to a fast one.
- Core Web Vitals are in a passing range.Run your landing page through PageSpeed Insights. LCP under 2.5s, CLS under 0.1. If you're nowhere close, find out why before you spend money on ads.
- Images are optimized. No 4MB PNGs in your hero section. Use modern formats (WebP, AVIF), serve appropriately sized images for the viewport, and use lazy loading for anything below the fold.
- Caching is set up for static assets. CDN-level caching for your JS, CSS, fonts, and images. If you're on Vercel or Netlify this is mostly automatic — but verify it.
- No N+1 queries.If you're looping over a list and making a database call inside the loop, you'll feel this at scale. Check your query patterns before users do.
- Bundle size is reasonable. Run a bundle analyzer. A 2MB JS bundle for a simple SaaS landing page is a red flag.
SEO & Discoverability
You can't get organic traffic if search engines can't find you or don't know what you are. These are the basics — ignoring them means you're actively working against yourself.
- Unique, descriptive
<title>and<meta description>on every page. Not the same tag copy-pasted. Not blank. Actual descriptions that match the content. - Open Graph tags are set.
og:title,og:description,og:image. Test them with the LinkedIn Post Inspector or the Twitter Card Validator before you share your link anywhere. /sitemap.xmlexists and is submitted to Google Search Console. If Google doesn't know your pages exist, they won't rank./robots.txtis correct. At minimum, it should not be blocking crawlers from your public pages. Check this — it's a surprisingly common mistake.- Canonical tags where needed. If the same content is accessible at multiple URLs, pick one and point to it.
- Structured data for your content type.If you're a SaaS, at minimum set up Organization schema. If you have blog posts, use Article schema.
Payments & Data
If you're charging real money or storing real user data, this section is non-negotiable. Not “nice to have” — legally and ethically required depending on your jurisdiction.
- Stripe webhooks are verified.Don't trust the data in a webhook payload without verifying the signature. Unverified webhooks are a vector for fraud and inventory manipulation.
- Subscription and payment state is handled for edge cases. What happens when a payment fails? When a subscription is cancelled mid-cycle? When a refund is issued? These flows need to work.
- You have database backups, and you've tested restoring from them. A backup you've never restored from is a backup you don't actually have. Set up automated backups and run a restore drill.
- You have a privacy policy and it's accurate. If you're using any analytics, storing emails, or processing payments, you need one. Don't copy-paste one that doesn't reflect what you actually do.
- GDPR basics are covered if you have EU users. At minimum: a privacy policy, a way for users to request deletion of their data, and cookie consent if you're setting non-essential cookies.
- PII is handled with care.User emails, names, payment info — know where it lives, who can access it, and that it's not accidentally ending up in logs or error reports.
How to Actually Use This
Don't just read it and feel vaguely guilty about the things you haven't done. That's not the point.
Go through each section and mark every item as one of three things: done, not applicable, or needs work. The “needs work” column is your actual to-do list. Prioritize security and reliability first — those are the ones that cause incidents. Performance and SEO matter for growth, but a security hole or a missing backup will cost you far more than a slow page.
If you're pre-launch, block an afternoon before you flip the switch. Run through the full list. The things that take five minutes are worth doing now; the ones that take longer — set a deadline and treat them as launch blockers or immediate post-launch tasks.
If you're already live, this still applies. Ship in order of risk. Security and payments items that aren't checked off should be tickets this week, not someday.
One practical note: the security section is the hardest to audit manually, especially if you're working quickly or with AI-generated code. gitdoctor.iocan scan your repository automatically for hardcoded secrets, vulnerable patterns, and exposed credentials — things that are genuinely easy to miss when you're moving fast. Run it before your next push.
Ship It — But Know What You're Shipping
Getting to “done” is hard. Most side projects never make it to production, and if yours did, that's something. Don't let perfect be the enemy of shipped.
But there's a version of moving fast that's reckless, and a version that's disciplined. The disciplined version ships just as quickly — it just takes an honest look at what's actually in place before the users show up.
Work through the list. Fix the critical gaps. Then ship with confidence instead of fingers crossed.