<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/ETSkfWJ78" -->

---
title: How to Build a Deployment Checklist That Actually...
description: A deployment checklist should split into two columns: application risk (schema changes, background worker payload compatibility, cache serialization, rollback...
canonical: https://daily.dev/posts/how-to-build-a-deployment-checklist-that-actually-prevents-production-incidents-etskfwj78
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: How to Build a Deployment Checklist That Actually Prevents Production Incidents | daily.dev
og:description: A deployment checklist should split into two columns: application risk (schema changes, background worker payload compatibility, cache serialization, rollback...
og:url: https://daily.dev/posts/how-to-build-a-deployment-checklist-that-actually-prevents-production-incidents-etskfwj78
og:image: https://api.daily.dev/og/posts/ETSkfWJ78.png
og:image:alt: How to Build a Deployment Checklist That Actually Prevents Production Incidents
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# How to Build a Deployment Checklist That Actually Prevents Production Incidents

**[freeCodeCamp](https://daily.dev/sources/freecodecamp)** · 16 min read · 7 upvotes · 1 comments

## Summary

A deployment checklist should split into two columns: application risk (schema changes, background worker payload compatibility, cache serialization, rollback triggers) that only your team can judge, and infrastructure risk (certificates, image provenance, autoscaling, log shipping) that should be automated rather than checked by hand. Covers the expand-and-contract pattern for safe database migrations, separating deploy from release using feature flags, setting rollback triggers before shipping, and using Kubernetes startup/readiness probes to avoid cold-start restart loops. Argues that infrastructure-column items that can't be automated point toward needing an internal delivery platform or a PaaS, and recommends tracking DORA metrics to validate whether the checklist is working.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.freecodecamp.org/news/how-to-build-a-deployment-checklist-that-actually-prevents-production-incidents>

## Questions this post answers

### How do I safely rename a database column without breaking production, like renaming users.name to users.full_name?

Use the expand-and-contract pattern across four separate deploys: first add the new nullable column with no default (avoiding a table rewrite or long lock), then deploy code that writes to both columns while still reading the old one, backfill existing rows in batches of a few thousand at a time, then deploy code that reads the new column with a fallback to the old one for safe rollback, and only weeks later, once nothing references the old column, drop it.

_Developers working through multi-step schema migrations can find similar deployment patterns and pitfalls on daily.dev._

### How do I prevent a background worker from failing when I change the shape of a job payload during deployment?

Send both the old and new payload shapes for one release so either the old or new consumer version can read the message correctly, then deploy the new consumer, let the queue drain, and remove the old key in a later release. Without this, a new producer writing a changed payload key (like removing customer_id) causes the still-running old consumer to throw a KeyError, and jobs fail silently into a dead letter queue.

_Anyone debugging silent queue failures during rolling deploys can compare backward-compatibility patterns on daily.dev._

### What is the difference between Kubernetes readiness probes and startup probes and why does it matter for slow-starting apps?

Startup probes give a generous grace period for the first boot only, while readiness probes use a tighter window once the app is already running, and confusing the two causes an app needing 40 seconds to warm up to be killed by a readiness probe with only a 30-second failure threshold, triggering an endless restart loop. Splitting them apart, for example a startup probe with failureThreshold 18 (90 seconds) followed by a stricter readiness probe, fixes this cold-start capacity problem.

_Engineers tuning Kubernetes rollout configs to avoid restart loops can track probe patterns like this on daily.dev._

## Community discussion

Top comments from developers on daily.dev.

**@leonidbugaev** · 0 upvotes

> The send_invoice dual payload is the item I'd keep. customer_id stays next to the nested customer object until the old consumer is gone, otherwise that KeyError just lands in the DLQ a few hours later.

## Similar posts on daily.dev

- [The Production Deployment Checklist: 50\+ Things Senior Backend Engineers Check Before Shipping to Production](https://daily.dev/posts/the-production-deployment-checklist-50-things-senior-backend-engineers-check-before-shipping-to-pr-t8nzjgoik) · Medium · 0 upvotes · 0 comments
- [Continuous Delivery Office Hours Ep.5: Delivering database changes](https://daily.dev/posts/continuous-delivery-office-hours-ep-5-delivering-database-changes-qzfxcmmhw) · OctopusDeploy · 0 upvotes · 0 comments

---

Tags: [#kubernetes](https://daily.dev/tags/kubernetes), [#database](https://daily.dev/tags/database), [#cicd](https://daily.dev/tags/cicd)

[View this post on daily.dev](https://daily.dev/posts/how-to-build-a-deployment-checklist-that-actually-prevents-production-incidents-etskfwj78)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"How to Build a Deployment Checklist That Actually Prevents Production Incidents","url":"https://daily.dev/posts/how-to-build-a-deployment-checklist-that-actually-prevents-production-incidents-etskfwj78","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/how-to-build-a-deployment-checklist-that-actually-prevents-production-incidents-etskfwj78"},"datePublished":"2026-09-09T22:05:31.495Z","dateModified":"2026-09-14T06:45:22.490Z","description":"A deployment checklist should split into two columns: application risk (schema changes, background worker payload compatibility, cache serialization, rollback...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/d005d3ad524589411ca21fbcd2715597?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/d005d3ad524589411ca21fbcd2715597?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"freeCodeCamp","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"freeCodeCamp","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1628412854/logos/freecodecamp","url":"https://daily.dev/sources/freecodecamp"},"commentCount":1,"discussionUrl":"https://daily.dev/posts/how-to-build-a-deployment-checklist-that-actually-prevents-production-incidents-etskfwj78","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":7},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":1}],"keywords":"kubernetes,database,cicd","timeRequired":"PT16M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"freeCodeCamp","item":"https://daily.dev/sources/freecodecamp"},{"@type":"ListItem","position":3,"name":"How to Build a Deployment Checklist That Actually Prevents Production Incidents"}]}
{"@context":"https://schema.org","@type":"WebPage","@id":"https://daily.dev/posts/how-to-build-a-deployment-checklist-that-actually-prevents-production-incidents-etskfwj78","comment":[{"@type":"Comment","text":"The send_invoice dual payload is the item I’d keep. customer_id stays next to the nested customer object until the old consumer is gone, otherwise that KeyError just lands in the DLQ a few hours later.","datePublished":"2026-09-10T07:12:10.053Z","url":"https://daily.dev/posts/ETSkfWJ78#c-nKXJw4Ddg","author":{"@type":"Person","name":"Leonid Bugaev","url":"https://daily.dev/leonidbugaev","image":"https://lh3.googleusercontent.com/a/ACg8ocLhMgurwTmJElWaH9A8Ju8cHvZxgMCDt009jEYkmFCyUGAoaGSw=s96-c"}}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/how-to-build-a-deployment-checklist-that-actually-prevents-production-incidents-etskfwj78#faq","mainEntity":[{"@type":"Question","name":"How do I safely rename a database column without breaking production, like renaming users.name to users.full_name?","acceptedAnswer":{"@type":"Answer","text":"Use the expand-and-contract pattern across four separate deploys: first add the new nullable column with no default (avoiding a table rewrite or long lock), then deploy code that writes to both columns while still reading the old one, backfill existing rows in batches of a few thousand at a time, then deploy code that reads the new column with a fallback to the old one for safe rollback, and only weeks later, once nothing references the old column, drop it. Developers working through multi-step schema migrations can find similar deployment patterns and pitfalls on daily.dev."}},{"@type":"Question","name":"How do I prevent a background worker from failing when I change the shape of a job payload during deployment?","acceptedAnswer":{"@type":"Answer","text":"Send both the old and new payload shapes for one release so either the old or new consumer version can read the message correctly, then deploy the new consumer, let the queue drain, and remove the old key in a later release. Without this, a new producer writing a changed payload key (like removing customer_id) causes the still-running old consumer to throw a KeyError, and jobs fail silently into a dead letter queue. Anyone debugging silent queue failures during rolling deploys can compare backward-compatibility patterns on daily.dev."}},{"@type":"Question","name":"What is the difference between Kubernetes readiness probes and startup probes and why does it matter for slow-starting apps?","acceptedAnswer":{"@type":"Answer","text":"Startup probes give a generous grace period for the first boot only, while readiness probes use a tighter window once the app is already running, and confusing the two causes an app needing 40 seconds to warm up to be killed by a readiness probe with only a 30-second failure threshold, triggering an endless restart loop. Splitting them apart, for example a startup probe with failureThreshold 18 (90 seconds) followed by a stricter readiness probe, fixes this cold-start capacity problem. Engineers tuning Kubernetes rollout configs to avoid restart loops can track probe patterns like this on daily.dev."}}]}
```

