You built the thing.
It works on localhost. The auth flow feels smooth. Your database queries return what you expect. Stripe test mode processes payments perfectly. You're 48 hours into a coding marathon and ready to ship.
Stop right there.
“Works on localhost” and “ready for paying customers” are very different things. You can miss up to 30 high-impact checks and still feel fast and confident.
Here's your pre-launch checklist, organized like ShipCheck runs its scans.
🔒 Security
✅ HTTPS Everywhere (No HTTP)
Check: Ensure ALL routes redirect to HTTPS, including API endpoints and subdomains.
Why it matters: Plain HTTP sends cookies and login tokens in clear text and exposes user data on any shared network.
module.exports = {
async redirects() {
return [
{
source: '/:path*',
has: [{ type: 'host', value: 'http' }],
destination: 'https://:host/:path*',
permanent: true,
},
];
},
};✅ Environment Variables Secured
Check: Keep API keys, DB passwords, and secrets out of your git history and out of source files.
Why it matters: Leaks usually start with a single hard-coded token in client or server bundles.
✅ .env Files Blocked
Check: Return a 404 for `/.env` and similar sensitive files.
Why it matters: A single exposed environment file gives attackers a complete reconnaissance map in one request.
✅ Rate Limiting on Sensitive Endpoints
Check: Apply low request budgets to login, signup, and checkout endpoints.
Why it matters: Without limits, bots can lock out real users and brute force credentials.
✅ Security Headers Configured
Check: Set CSP, HSTS, X-Frame-Options, X-Content-Type-Options, and Referrer-Policy.
Why it matters: Headers are cheap protection against whole classes of XSS, clickjacking, and MITM.
✅ Error Pages Don't Leak Info
Check: Use generic production errors for users and capture stack traces in logs only.
Why it matters: Stack traces give attackers exact files, stack versions, and attack surface.
💳 Payments
✅ Live API Keys in Production
Check: Move `pk_test_*` and `sk_test_*` keys to production-only live credentials.
Why it matters: Test credentials silently fail in real card flows and create revenue blind spots.
✅ Webhook Signature Verification
Check: Verify incoming signatures before applying webhook side effects.
Why it matters: Without verification, fake events can enable free accounts or fake payment events.
✅ Webhook Idempotency
Check: Make webhook handlers idempotent before processing side effects.
Why it matters: Retry delivery is normal; duplicate events should never create duplicate purchases.
✅ Payment Failure Handling
Check: Notify users on failed payment events and implement retry queues for transient failures.
Why it matters: One network hiccup should not become a silent $0 conversion loss.
✅ Tax Calculation Configured
Check: Validate tax settings for the regions you serve.
Why it matters: Incorrect tax treatment creates legal and financial risk quickly.

🔑 Auth
✅ Password Hashing (Not Plain Text)
Check: Hash passwords with bcrypt or Argon2 and never store plaintext.
Why it matters: Plaintext credentials reduce one breach into instant account compromise.
✅ Secure Session Management
Check: Use `httpOnly` and secure cookies for session tokens.
Why it matters: Client-side storage for tokens is exposed to XSS abuse.
✅ Token Expiration Configured
Check: Set short-lived access tokens and rotating refresh flows.
Why it matters: Long-lived tokens turn one theft into permanent account compromise.
✅ Logout Actually Revokes Access
Check: Invalidate tokens server-side during logout actions.
Why it matters: Clearing localStorage does not invalidate stolen session artifacts elsewhere.
✅ Strong Password Requirements
Check: Require complexity and reject common weak patterns (`password123`, `123456`).
Why it matters: Weak credentials are still the most common vector in small teams.
🔍 SEO
✅ Meta Tags on Every Page
Check: Use complete title, description, and Open Graph tags site-wide.
Why it matters: Missing metadata makes your pages look broken in search and social previews.
✅ Sitemap Generated
Check: Keep a live sitemap and verify crawler visibility in Search Console.
Why it matters: Without one, discovery slows and ranking signal quality drops.
✅ Robots.txt Configured
Check: Block API, admin, and internal routes from indexing.
Why it matters: You don’t want private surfaces exposed in public search indexes.
✅ Canonical URLs Set
Check: Add canonical tags for duplicate routes and parameterized variants.
Why it matters: Canonicalization preserves link equity and avoids duplicate content penalties.
✅ Page Speed Optimized
Check: Monitor Lighthouse and keep mobile performance within modern thresholds.
Why it matters: Speed impacts rank and conversion; slower pages drop both.
✅ Mobile Responsive Design
Check: Test major mobile breakpoints and interaction flows.
Why it matters: Most users are now mobile; a broken mobile UI is a direct revenue leak.

⚡ Performance
✅ Images Optimized and Lazy-Loaded
Check: Use compressed formats and defer non-critical images.
Why it matters: Poor media strategy can double load time and hurt Core Web Vitals.
<!-- Example: defer non-critical images -->
<img src="/hero.png" loading="lazy" alt="..." />✅ CSS and JS Minified
Check: Keep bundles production-minified and chunked.
Why it matters: Every extra KB directly impacts time-to-interactive.
✅ Gzip/Brotli Compression Enabled
Check: Enable compression at CDN or server layer.
Why it matters: Text payloads commonly shrink by 60-80% when compressed.
✅ CDN Configured
Check: Use a global CDN for static assets and API caching where appropriate.
Why it matters: CDN latency reduction is the fastest route to smoother global UX.
✅ Database Queries Indexed
Check: Index frequently queried columns and critical join keys.
Why it matters: Indexing can separate an app from 50ms and 5000ms response times.

🏥 Uptime
✅ Health Endpoint Implemented
Check: Expose a status endpoint that validates key dependencies.
Why it matters: Monitors need a signal to alert before users notice.
✅ Error Tracking Configured
Check: Pipe exceptions into Sentry, LogRocket, or equivalent.
Why it matters: Unseen errors become unresolved incidents by default.
✅ Uptime Monitoring Active
Check: Hook into at least one external uptime monitor.
Why it matters: Synthetic checks catch regional or DNS-level failures quickly.
✅ Backup Strategy Tested
Check: Rehearse recovery from real backups, not documentation-only plans.
Why it matters: Backup without restoration testing is not a disaster plan.

The Hard Truth
That's 30+ items.
Most solo developers check few of them before launch.
If you check only what you can see right now in your browser, you're shipping without a net. That works until it doesn't. When something breaks at 3 AM, there is no second chance.
Ready to make your production readiness easier to enforce?
ShipCheck can verify many of these checks automatically and prioritize what to fix first.
Scan Your App Now