You built the feature. Tests pass. Staging looks good. Time to ship, right?
Not so fast. I've shipped enough broken things to know that there's a gap between "it works" and "it's ready." This is my checklist — the things I verify before every launch.
Not everything applies to every project. Skip what's irrelevant. But scan the whole list at least once.
Performance
- [ ] Page loads in under 3 seconds on a throttled connection (Chrome DevTools → Network → Slow 3G)
- [ ] Images are optimized — use WebP/AVIF, lazy-load below-the-fold images, serve responsive sizes
- [ ] No render-blocking resources — CSS and JS that block first paint are deferred or inlined
- [ ] Bundle size is reasonable — run
npx bundlephobiaor check your framework's build output - [ ] API responses are fast — P95 latency under 500ms for critical endpoints
- [ ] Caching headers are set — static assets have
Cache-Control: public, max-age=31536000, immutablewith hashed filenames
SEO & Social Sharing
- [ ] Every page has a unique
<title>— under 60 characters, descriptive - [ ] Every page has a
<meta description>— 120-160 characters - [ ] Open Graph tags are set —
og:title,og:description,og:image(1200x630px, absolute URL) - [ ] Twitter Card tag is set —
twitter:card=summary_large_image - [ ] og:image works — test with Facebook Sharing Debugger
- [ ] Canonical URLs are set —
<link rel="canonical">on every page - [ ] robots.txt exists — allows indexing of public pages, blocks admin/API routes
- [ ] sitemap.xml exists — lists all public URLs
- [ ] Structured data is valid — test with Google's Rich Results Test
Security
- [ ] HTTPS everywhere — no mixed content, HSTS header set
- [ ] No secrets in client code — API keys, tokens, and passwords are server-side only
- [ ] Input validation — all user input is validated server-side (don't trust client validation)
- [ ] SQL injection protected — use parameterized queries, never string concatenation
- [ ] XSS protected — user content is escaped before rendering in HTML
- [ ] CSRF protection — state-changing requests require a CSRF token
- [ ] Rate limiting — login, registration, and API endpoints have rate limits
- [ ] CORS configured — only your domains are allowed, not
*in production - [ ] Dependencies audited — run
npm auditorpip audit, fix critical vulnerabilities - [ ] No .env or credentials in the repository — check with
git log --all -p | grep -i 'password\|secret\|api_key'
Accessibility
- [ ] All images have alt text — descriptive for content images, empty for decorative ones
- [ ] Keyboard navigation works — tab through the entire page, ensure all interactive elements are reachable
- [ ] Color contrast passes — use Chrome DevTools accessibility audit or axe-core
- [ ] Form labels exist — every
<input>has an associated<label> - [ ] Focus indicators are visible — don't remove
:focusoutlines without replacing them
Error Handling
- [ ] 404 page exists — custom, helpful, includes navigation back to the main site
- [ ] 500 errors don't leak stack traces — production error pages are generic
- [ ] API errors return consistent format —
{ error: "message" }with appropriate HTTP status codes - [ ] Error monitoring is set up — Sentry, LogRocket, or similar
Mobile
- [ ] Viewport meta tag is set —
<meta name="viewport" content="width=device-width, initial-scale=1.0"> - [ ] Tested on real devices — or at minimum, Chrome DevTools device emulation
- [ ] Touch targets are large enough — minimum 44x44px for buttons and links
- [ ] No horizontal scroll — nothing overflows the viewport
Monitoring & Analytics
- [ ] Uptime monitoring — UptimeRobot (free), Pingdom, or similar
- [ ] Analytics installed — you know how many people visit and where they come from
- [ ] Error tracking — you get notified when things break
- [ ] Performance monitoring — track Core Web Vitals over time
Launch Day
- [ ] DNS is configured — if using a custom domain, records are set and propagated
- [ ] SSL certificate is valid — not expired, covers all subdomains you use
- [ ] Redirects work — old URLs redirect to new ones (301, not 302)
- [ ] Backup exists — database backup taken before any migration
- [ ] Rollback plan — you know how to revert if things go wrong
- [ ] Team is online — someone is available to respond to issues
The Meta-Checklist
Before using this checklist:
- Don't let it block you from shipping. A shipped product with imperfect SEO tags beats a perfect product that never launches.
- Prioritize by impact. Security issues > broken functionality > performance > SEO > nice-to-haves.
-
Automate what you can. Lighthouse CI, ESLint,
npm audit, and pre-commit hooks catch many of these automatically. - Revisit after launch. Some things (analytics data, real-world performance) can only be evaluated after real users interact with your product.
Tools I Use for Each Category
| Category | Tool | Free? |
|---|---|---|
| Performance | Lighthouse, WebPageTest | Yes |
| SEO | Google Search Console, Ahrefs Webmaster | Yes |
| OG Tags | Facebook Sharing Debugger, metadata extraction APIs | Yes |
| Security | npm audit, Snyk, OWASP ZAP | Yes |
| Accessibility | axe DevTools, Lighthouse | Yes |
| Monitoring | UptimeRobot, Sentry (free tier) | Yes |
| Analytics | Plausible, Umami, Cloudflare Analytics | Varies |
Print It, Pin It
I keep a printed copy of this next to my monitor. Every time I'm about to click "Deploy," I scan through it. It takes 5 minutes and has saved me from embarrassing launches more times than I can count.
What's on your pre-launch checklist that I missed? I'm always looking to improve mine.
Top comments (0)