From Local to Production: My Deployment Checklist

by Ravi Ranjan, Full-Stack Developer

Deploying to production shouldn't feel like defusing a bomb. But without a checklist, that's exactly what it feels like. Here's the checklist I follow every time - no drama, just ship it.

Why You Need a Checklist

Look, I get it. You've deployed dozens of times. You know what you're doing. But that's exactly when things slip through. A checklist isn't about doubting your skills - it's about making deployments boring and predictable. And boring is good when you're shipping code to production.

1. Pre-Deployment: Don't Skip the Boring Stuff

Environment Variables

All secrets in environment variables. Not hardcoded. This should be obvious in 2024, but I still see it.

# Bad
const stripeKey = "sk_live_abc123..."

# Good
const stripeKey = process.env.STRIPE_SECRET_KEY

Checklist:

  • All API keys moved to .env file
  • .env.example created (for your future self or teammates)
  • Production secrets stored securely (1Password, AWS Secrets Manager, etc.)
  • Double-check database URLs - staging vs production URLs look similar

Code Cleanup

Run your linter. Yes, right now. npm run lint or whatever you use.

Remove debug console.log statements. Or at least the ones logging sensitive data. Your production logs don't need to know what user.password is.

Delete commented-out code blocks. If you haven't needed it in 3 months, you won't. That's what git history is for.

No "TODO: fix before production" comments. Just fix it now. Or create a proper ticket and remove the comment.

Checklist:

  • Linter passed without errors
  • No sensitive data in console.logs
  • Commented-out code removed
  • TODO comments addressed or ticketed

Dependencies

npm audit

Fix the critical vulnerabilities. The rest? Use your judgment. Not every moderate severity issue needs immediate attention, but the critical ones? Yeah, those matter.

Remove unused packages. They're just dead weight slowing down your installs and increasing your bundle size.

Check for deprecated packages. Future headaches waiting to happen.

Checklist:

  • npm audit run, critical issues fixed
  • Unused dependencies removed
  • No deprecated packages (or documented exceptions)
  • Dev dependencies properly separated from production dependencies

Database

Test your migrations. In staging. Not production. Please.

Have a backup strategy. You DO have backups, right? Right?

Add database indexes where your queries need them. Your future self dealing with slow queries will thank you.

Checklist:

  • Database migrations tested in staging environment
  • Rollback scripts ready (know how to undo migrations)
  • Indexes added for performance-critical queries
  • Backup strategy confirmed and tested

2. Testing: Because Murphy's Law is Real

Build the Actual Production Bundle

Don't just test in development mode. Build and test the production bundle locally.

npm run build
npm start # or however you run production locally

Development and production builds are different beasts. CSS might work differently. Environment variables might behave differently. Assets might load from different paths.

Clear your browser cache and test again. Cache lies. Always.

Checklist:

  • Production bundle builds without errors
  • Production bundle tested locally
  • Tested with cleared browser cache
  • No hardcoded URLs pointing to localhost

Cross-Device Reality Check

Test on mobile. Both iOS and Android if you can manage it. Desktop-only testing is a trap.

Tablets exist. People still use them. Check how your layout responds.

Different screen sizes matter. Not everyone has a 27-inch monitor.

Checklist:

  • Tested on iOS mobile device
  • Tested on Android mobile device (or Chrome DevTools mobile emulation)
  • Tablet view checked
  • Responsive breakpoints working correctly

Edge Cases Worth Testing

Slow internet: Throttle your connection in DevTools. See what breaks. Does your app show loading states? Or does it just sit there silently?

API down: Kill your backend. See if your frontend handles it gracefully. Does it show an error message? Or does it just hang?

Empty states: What does a brand new user see? Do you handle zero data gracefully?

Maximum data: What if someone has 10,000 items in a list? Does your pagination work? Or does the browser crash?

Checklist:

  • Tested with throttled network (3G speed)
  • Tested with backend API unavailable
  • Empty state UI works (new user experience)
  • Large datasets handled properly (pagination, virtualization)
  • Forms validated correctly (try submitting invalid data)

Integration Checkpoints

Third-party APIs: Are they configured for production? Stripe test keys won't charge real cards. Make sure you're using production credentials.

Webhooks: Are they pointing to your production domain? Not localhost:3000?

CORS: This one's always fun. Test that your frontend can actually talk to your backend in production.

Checklist:

  • Third-party API keys switched to production
  • Webhooks configured with production URLs
  • CORS settings allow production domain
  • Email service configured (not sending test emails to real users)

3. Security: The Checklist Within the Checklist

Authentication

Password requirements enforced. Whatever makes sense for your app - length, complexity, whatever. Just enforce it consistently.

Rate limiting on login endpoints. Brute force attacks are still a thing in 2024, apparently.

JWT expiration times: Not 10 years. Not 5 minutes. Something reasonable like 15 minutes with a refresh token strategy.

Test password reset flow. Does it actually work? Does the email get sent?

Checklist:

  • Password requirements enforced on backend (not just frontend)
  • Rate limiting configured on authentication endpoints
  • JWT/session expiration times reasonable
  • Password reset flow tested end-to-end
  • Invalid/expired token handling tested

Data Protection

HTTPS enforced. Redirect all HTTP traffic to HTTPS. Yes, this is still necessary in 2024.

Security headers configured. If you're using Node/Express, helmet.js does this for you.

const helmet = require('helmet')
app.use(helmet())

Input validation on ALL endpoints. Don't trust the frontend to validate. Validate on the backend too.

File upload restrictions: Size limits, type checking. Don't let users upload 5GB files or executable scripts.

Checklist:

  • HTTPS enforced (HTTP redirects to HTTPS)
  • Security headers configured (helmet.js or equivalent)
  • Input validation on all API endpoints
  • File upload size and type restrictions
  • SQL injection prevention in place

Basic Security Tests

Try some classic SQL injection:

username: admin' OR '1'='1

Test XSS prevention. Throw some <script>alert('xss')</script> into your inputs.

Check what data your API exposes. Make sure secrets aren't in API responses. Check your error messages - they shouldn't leak sensitive information.

Checklist:

  • SQL injection attempts blocked
  • XSS attempts sanitized
  • API responses don't expose secrets
  • Error messages don't leak system information
  • Authentication required where needed

4. Performance: Make It Fast Enough

Frontend Optimization

Images: Optimize them. Use WebP format where supported. Compress them. A 5MB PNG is never necessary for a blog header.

<picture>
  <source srcset="image.webp" type="image/webp" />
  <img src="image.jpg" alt="Description" />
</picture>

Lazy loading: Images below the fold don't need to load immediately.

<img src="image.jpg" loading="lazy" alt="Description" />

Code splitting: Don't load your entire app upfront. Split it. Use dynamic imports.

const Dashboard = lazy(() => import('./Dashboard'))

Remove unused CSS: Especially if you're using Tailwind. PurgeCSS is your friend.

Font loading: Use font-display: swap so text renders while fonts load.

@font-face {
  font-family: 'CustomFont';
  src: url('font.woff2') format('woff2');
  font-display: swap;
}

Checklist:

  • Images optimized and compressed
  • Lazy loading implemented for below-fold images
  • Code splitting configured
  • Unused CSS removed
  • Font loading optimized (font-display: swap)
  • Bundle size analyzed and reasonable

Backend Optimization

N+1 queries: The silent performance killer. Eager load your relationships.

// Bad - N+1 query
const users = await User.findAll()
for (let user of users) {
  user.posts = await Post.findAll({ where: { userId: user.id } })
}

// Good - Single query with join
const users = await User.findAll({ include: Post })

Caching: Redis, CDN, browser caching - whatever fits your stack. Cache what makes sense.

API response times: Most endpoints should respond in under 200ms. If they don't, investigate.

Background jobs: Heavy tasks like sending emails, generating PDFs, processing images - move them to background jobs. Don't make users wait.

Checklist:

  • No N+1 database queries
  • Caching strategy implemented
  • API response times acceptable (under 200ms average)
  • Heavy tasks moved to background jobs
  • Database connection pooling configured

Monitoring Setup

Install error tracking. Sentry, Bugsnag, Rollbar - pick one. You need to know when things break.

Server monitoring for CPU, memory, disk space. You want to know about problems before users do.

Log aggregation. CloudWatch, Datadog, or just good old SSH - but have a way to see what's happening.

Checklist:

  • Error tracking installed (Sentry, Bugsnag, etc.)
  • Server monitoring configured
  • Log aggregation set up
  • Alerts configured for critical issues
  • Uptime monitoring enabled

5. Infrastructure: Where the Magic Happens

Server Basics

SSL certificate: Let's Encrypt is free and automatic. There's no excuse not to have HTTPS in 2024.

Firewall: Configure it. Only necessary ports open. SSH (22), HTTP (80), HTTPS (443) - that's usually it.

Server timezone: Set it to UTC. Always UTC. Not your local timezone. Not America/New_York. UTC. Trust me on this one.

Automated backups: Daily minimum. Weekly is not enough. You want to be able to restore from yesterday, not last week.

Checklist:

  • SSL certificate installed and auto-renewing
  • Firewall configured (only necessary ports open)
  • Server timezone set to UTC
  • Automated backups enabled (daily minimum)
  • Enough disk space for growth (at least 30% free)

Domain & DNS

DNS records pointing to the right place. A records for your domain, CNAME for www (or vice versa).

TTL values set reasonably. 3600 (1 hour) is fine for most cases. You can lower it before making changes.

If you're sending emails: SPF and DKIM records configured. Otherwise, your emails end up in spam.

Checklist:

  • Domain DNS records configured correctly
  • TTL values set appropriately
  • Email DNS records (SPF, DKIM) if sending emails
  • DNS propagation verified (use tools like whatsmydns.net)

CI/CD

Tests run automatically before deployment. If tests fail, deployment doesn't happen.

Build succeeds in CI environment, not just on your laptop.

Rollback process tested. You should be able to rollback quickly if needed.

Checklist:

  • Automated tests run on every commit
  • Build succeeds in CI environment
  • Deploy pipeline configured
  • Rollback process documented and tested
  • Deploy keys properly configured

6. Deployment Day: Ship It

Timing Matters

Deploy during low-traffic hours. For most apps, that's early morning.

NOT Friday at 5 PM. Unless you enjoy working weekends.

Notify your team about the deployment window. Especially if there might be brief downtime.

Checklist:

  • Deployment scheduled during low-traffic hours
  • Team notified about deployment window
  • Not Friday afternoon (seriously)
  • Key stakeholders aware

Pre-Flight Checks

Check server resources. Enough disk space? Enough memory? Don't deploy when you're at 95% disk usage.

Current version tagged in git. You need a reference point for rollback.

git tag -a v1.2.0 -m "Version 1.2.0 - Feature X"
git push origin v1.2.0

Staging environment tested thoroughly. Everything that can be tested in staging should be tested in staging.

Checklist:

  • Server has adequate resources (disk, memory, CPU)
  • Current version tagged in git
  • Staging environment tested thoroughly
  • Deployment runbook ready

During Deployment

Database migrations first, if you have any. Migrate, then deploy code.

npm run migrate
npm run deploy

Monitor logs in real-time. Keep that terminal open. Watch for errors.

Error tracking dashboard open. Sentry, Bugsnag, whatever you use - keep it visible.

Checklist:

  • Database migrations executed successfully
  • Code deployed without errors
  • Logs monitored in real-time
  • No immediate error spikes

Smoke Tests

Run these immediately after deploying:

Homepage loads: The most basic test. Does the homepage load?

User login/registration works: Can users actually sign in?

Critical flows: Whatever is mission-critical for your app. Checkout? Form submission? Document upload? Test it.

API health endpoint: If you have one, check it.

curl https://yourapi.com/health

Static assets loading: CSS, JavaScript, images - make sure they're all loading.

Checklist:

  • Homepage loads correctly
  • User authentication works
  • Critical user flows tested
  • API endpoints responding
  • Static assets loading (CSS, JS, images)
  • No console errors in browser

7. Post-Deploy: The First 24 Hours

Active Monitoring

Watch error rates. A small spike is normal. A sudden jump to 20% error rate? That's a problem.

Server metrics: CPU spikes? Memory leaks? Watch for unusual patterns.

Database performance: Slow queries suddenly appearing? Connection pool maxed out?

User feedback: Support tickets, Twitter mentions, email complaints - keep an eye on all channels.

Analytics: Traffic patterns looking normal? Bounce rate suddenly higher?

Checklist:

  • Error rates within normal range (less than 1%)
  • Server metrics stable (CPU, memory, disk)
  • Database performance normal
  • No unusual user complaints
  • Analytics showing normal patterns
  • Email delivery working (check spam folder too)

Communication

Announce to your team: "Deployed successfully to production."

Update your changelog if you maintain one.

Alert customer support about any changes they should know about.

Checklist:

  • Team notified of successful deployment
  • Changelog updated
  • Customer support briefed on changes
  • Documentation updated if needed

Cleanup

Remove old feature flags if you're using them.

Archive old logs. Keep the last 30 days accessible, archive the rest.

Document what went well and what didn't. Make notes for next time.

Checklist:

  • Old feature flags removed
  • Old logs archived
  • Deployment notes documented
  • Post-mortem scheduled (if issues occurred)

8. Rollback Plan: Hope for Best, Prepare for Worst

Know How to Undo

Previous version tagged in git. You did this in the pre-flight checks, right?

git checkout v1.1.0
npm run deploy

Rollback command ready and tested. You should have rolled back in staging at least once.

Database rollback scripts prepared. Not all migrations are easily reversible. Plan accordingly.

Contact information handy. If things go really wrong, who do you call? Have phone numbers ready, not just email addresses.

Checklist:

  • Previous version tagged and accessible
  • Rollback procedure documented
  • Database rollback scripts ready
  • Emergency contact list updated
  • Rollback tested in staging

When to Hit the Panic Button

Error rate spikes: Suddenly seeing 10%+ error rate? Something's wrong.

Critical feature broken: Can users not login? Can't checkout? Can't submit forms? Rollback.

Database performance tanks: Queries taking 10x longer than usual? Investigate quickly, rollback if needed.

Security vulnerability discovered: Someone found a hole? Patch it now or rollback until you can.

Rollback Decision Matrix

If error rate < 5%: Investigate, fix forward if possible.

If error rate > 5%: Consider rollback, investigate urgently.

If critical feature broken: Rollback immediately.

If performance degraded > 2x: Rollback, investigate root cause.

If security issue: Rollback immediately, patch, redeploy.


The Downloadable Checklist

Here's the condensed version you can copy-paste:

# Production Deployment Checklist

## Pre-Deployment

- [ ] Environment variables configured
- [ ] No hardcoded secrets
- [ ] Linter passed
- [ ] npm audit run, critical issues fixed
- [ ] Database migrations tested
- [ ] Dependencies up to date

## Testing

- [ ] Production build tested locally
- [ ] Mobile devices tested
- [ ] Slow connection tested
- [ ] API failure scenarios tested
- [ ] Empty and full states tested
- [ ] Third-party integrations verified

## Security

- [ ] HTTPS enforced
- [ ] Security headers configured
- [ ] Rate limiting enabled
- [ ] Input validation on all endpoints
- [ ] SQL injection prevention tested
- [ ] XSS prevention tested

## Performance

- [ ] Images optimized
- [ ] Lazy loading implemented
- [ ] Code splitting configured
- [ ] No N+1 queries
- [ ] Caching strategy in place
- [ ] Background jobs for heavy tasks

## Infrastructure

- [ ] SSL certificate installed
- [ ] Firewall configured
- [ ] Automated backups enabled
- [ ] DNS configured correctly
- [ ] Server timezone set to UTC
- [ ] CI/CD pipeline working

## Deployment

- [ ] Scheduled during low-traffic hours
- [ ] Team notified
- [ ] Server resources checked
- [ ] Current version tagged
- [ ] Staging tested thoroughly
- [ ] Migrations run successfully

## Smoke Tests (Immediately After)

- [ ] Homepage loads
- [ ] User login works
- [ ] Critical flows tested
- [ ] API responding
- [ ] Static assets loading
- [ ] No console errors

## Post-Deploy (First 24h)

- [ ] Error rates normal
- [ ] Server metrics stable
- [ ] Database performance good
- [ ] User feedback monitored
- [ ] Team notified of success

## Rollback Plan

- [ ] Previous version tagged
- [ ] Rollback procedure documented
- [ ] Database rollback scripts ready
- [ ] Emergency contacts available

Final Thoughts

Checklists make deployments boring. And boring is exactly what you want when shipping to production.

This list isn't exhaustive. Your app might need additional checks. Your infrastructure might require different steps. That's fine. Adapt this to your needs.

The goal isn't to follow this blindly. The goal is to make sure you don't skip the important stuff just because you're in a hurry or you've "done this a hundred times."

Got something I missed? Something that saved your deploy once? Drop it in the comments. Checklists get better with crowdsourcing.

Now go deploy something. And maybe not at 5 PM on Friday.

Let's build something amazing together

Have a project in mind? I'd love to hear about it. Let's discuss how I can help bring your ideas to life.

Quick Contact

  • Based in
    India
    Available for Remote Work
  • Contact
    [Enable JavaScript to view contact]