Harness reports that 72% of organizations have experienced a production incident caused by AI-generated code, while developers are shipping 63% faster. For a five-person team, that combination means a release can reach production before anyone has had time to decide who is allowed to stop it.

A useful release process is not a calendar meeting, a ticket status, or a long list of tools. It is a set of decisions that still works at 16:45 on a Friday when a deployment increases checkout failures and the engineer who wrote the change is in transit.

The checklist below is designed for teams of three to 15 engineers shipping a web application, API, or worker service. It assumes continuous integration, a production environment, and a team that can deploy through a CI/CD system such as GitHub Actions, GitLab CI, CircleCI, Jenkins, or a hosted deployment platform. Adapt the commands and metrics to your stack, but keep the ownership and stop conditions explicit.

1. Define a release as a bounded, reversible change

“Deploy main” is not a release definition. A release needs a specific scope: one immutable build, a known set of database changes, a rollout method, and a user-visible outcome that can be checked after deployment.

For example, a release record might say: “Build api:2026-09-03.4 adds an address-validation provider behind the address_validation_v2 flag. It changes no database schema. Initial exposure is 5% of authenticated checkout sessions.” That description tells the team what is being released, how broad the initial blast radius is, and the fastest available mitigation: disable the flag.

Do not group unrelated work simply because it is ready at the same time. A new billing webhook handler, an index migration, and a CSS fix have different failure modes and different rollback paths. Combining them produces the worst incident-review question: “Which of the three changes caused this?”

  • Small release: one service or feature area, one owner, and one clear success metric.
  • Risky release: authentication, payments, permissions, irreversible data changes, shared libraries, or infrastructure changes.
  • Release boundary: split risky changes into separate deployments, even if the product feature launches together.

The tradeoff is more deployment records and more short-lived feature flags. That administrative cost is usually lower than debugging a mixed release under customer pressure.

2. Create a release record before the merge queue starts

A small team does not need a release manager role. It does need one release record that answers operational questions without requiring a Slack archaeology session. Put it in the pull request, issue tracker, or a releases/ directory in the repository.

Use a template that is short enough to complete for every production change. If a field cannot be filled in, treat that as a release risk rather than leaving it blank. “Rollback: revert if broken” is not a plan when the release includes a background migration or a third-party API change.

Field Example Why it matters during an incident
Build identifier web:2026-09-03.4 Gives responders one artifact to compare, redeploy, or revert.
Release owner Priya, backend engineer Names the person running the checklist and making the first stop/go call.
Approver Marco, on-call engineer Ensures someone besides the author reviewed risk and rollback.
Rollout method 5%, then 25%, then 100% Prevents an accidental immediate full rollout.
Rollback action Disable flag; redeploy web:2026-08-29.2 Turns “roll back” into an executable action.
Success and stop metrics Checkout error rate; payment completion count Defines evidence instead of relying on intuition.

Link the exact commit SHA, pull request, deployment run, dashboard, and incident channel. The release record should take 10 minutes to prepare and save much more than 10 minutes when production behavior differs from staging.

3. Require test evidence, not a checkbox labeled “tested”

Automated testing should cover unit, integration, and end-to-end behavior where each level is appropriate, but “all tests passed” is incomplete evidence. A green pipeline can still test the wrong environment variable, mock the third-party failure you need to handle, or miss a migration that only fails against production-sized data.

For every release, record the test command or CI job URL and one sentence about the behavior that changed. For a payment retry change, that sentence could be: “Integration test confirms a provider timeout returns a retryable state and does not create a duplicate order.” That is more useful than a generic QA label.

  1. Run the repository’s required unit and static-analysis checks, such as npm test, pytest, or the equivalent CI workflow.
  2. Run an integration test against the real database engine and service contracts used in production where possible.
  3. Exercise one critical user path in a staging or preview environment: sign in, create a record, complete a checkout, or submit the changed workflow.
  4. Test the failure path introduced by the change: timeout, malformed input, authorization denial, duplicate request, or unavailable dependency.
  5. Attach results or links to the release record before approval.

If the change alters a database schema, test both application versions against the transitional schema. The safer sequence is usually expand, deploy compatible code, backfill if required, and contract later. A deployment that requires old code to disappear before the schema is valid is not rollback-ready.

4. Use approval gates that match risk, not hierarchy

Approval is useful when it checks a decision the author is poorly positioned to make alone. It is wasteful when it adds a mandatory manager click to a typo fix. The practical rule is: require a second technical approver whenever the release can affect money, access control, customer data, availability, or an irreversible state transition.

For low-risk changes, one peer review plus passing CI may be sufficient. For high-risk changes, require the release owner and the on-call engineer to approve the rollout plan. The on-call engineer is a particularly good approver because they inherit the operational consequences if the release misbehaves.

Change type Minimum approval Extra release condition
Copy, styling, isolated bug fix One code reviewer Required CI checks pass.
New API behavior or background job One code reviewer and release owner Staging path and failure path tested.
Payments, auth, permissions, customer data Code reviewer, release owner, on-call engineer Progressive rollout and written stop criteria.
Destructive migration or infrastructure change Two technical approvers including on-call Restore or forward-fix plan tested before production.

The second-order benefit is less interpersonal friction during incidents. When the stop conditions were approved before deployment, disabling a feature is a pre-agreed operational response, not a debate about whether someone is overreacting.

5. Assign deployment ownership and a communication channel

One person must own the release from “start deployment” through the initial observation window. That does not mean they wrote all the code or personally fix every alert. It means they are the coordinator: they run the checklist, announce rollout stages, decide whether criteria are met, and declare the release complete or rolled back.

Before deploying, name three roles. On a five-person team, one person may fill two roles, but do not leave any role unnamed.

  • Release owner: starts and monitors deployment; records decisions.
  • Technical backup: can execute rollback if the owner loses access or is pulled into debugging.
  • Business contact: confirms user impact for a customer-facing workflow, such as failed purchases or delayed notifications.

Create a release thread or channel before the deployment. A useful opening message includes the build ID, dashboard links, rollout stages, rollback command or runbook link, and observation period. For example: “Deploying api:2026-09-03.4; 5% for 15 minutes; watch checkout errors and provider timeout rate; rollback is flag-off followed by redeploy of api:2026-08-29.2.”

Do not make a production deployment depend on a private direct message. The timeline belongs in a shared location where the next on-call engineer can reconstruct what happened.

6. Deploy progressively when rollback is slower than exposure

Feature flags, canary releases, and blue-green deployments are all ways to control exposure. The right choice is not the most sophisticated mechanism; it is the one that reduces user impact faster than a bad release can spread.

Use a feature flag when code can safely exist in production without being enabled for everyone. Use a canary when the deployed artifact itself needs production validation, such as a runtime upgrade or a new request-routing layer. Use blue-green deployment when switching traffic between environments is safer than updating hosts in place. Modern release guidance consistently recommends these strategies because they enable gradual rollout and rapid rollback, but they do not eliminate the need to define who changes what.

For a small team, a simple staged rollout is enough:

  1. Deploy the immutable artifact with the feature disabled or exposed to 5% of traffic.
  2. Observe the selected metrics for 15 minutes or for enough real requests to exercise the path.
  3. Increase to 25% only if success criteria hold.
  4. Observe again, then move to 100%.
  5. Keep the release owner available through the agreed observation period.

A percentage is not magic. Five percent of a low-traffic internal application may produce no meaningful signal. In that case, route a known test account or internal cohort through the new path and perform an explicit smoke test before wider exposure.

7. Write rollback criteria as measurable stop conditions

The phrase “roll back if there are issues” fails because every production system has some errors. Your release record needs a comparison point, a threshold, and an action. Compare the new cohort with the pre-release baseline or with traffic still using the old version.

For a checkout release, define conditions such as: “Disable the feature immediately if checkout errors are higher for the enabled cohort than for the disabled cohort during the 15-minute observation window,” or “Stop rollout if payment-provider timeouts prevent a customer from completing the flow.” The exact metric varies by product; the key is that an engineer can act without waiting for executive interpretation.

Separate mitigation from rollback

A feature flag is mitigation: it stops users from reaching a bad code path. A rollback restores a prior artifact or configuration. Use the least disruptive safe action first, but record both steps. If disabling the flag does not reduce errors, redeploy the previous known-good artifact. If a schema expansion has already occurred, do not blindly restore an application version that cannot operate with the new schema.

Test the rollback procedure in a non-production environment at least once for risky changes. A command that looks plausible in a runbook is not a rollback capability until the team has verified permissions, artifact availability, and configuration compatibility.

8. Verify production behavior after the deployment says “successful”

A successful CI/CD job means the deployment system completed its actions. It does not mean customers can use the product. Post-release verification needs both technical signals and one direct user-path check.

Immediately after each rollout stage, check the service health endpoint, error logs, latency or saturation dashboard, and the business event that the release can affect. For an account-creation change, a 200 response is not enough; verify that a new account can sign in and receives the expected welcome flow. For a worker deployment, verify that a job is processed and that failures are routed as intended.

  • Confirm the running build ID or commit SHA in production.
  • Run one synthetic or manual smoke test through the changed workflow.
  • Compare application errors with the pre-release period.
  • Check the business outcome: completed checkout, created account, delivered message, processed job, or generated report.
  • Review support, customer-success, or internal operations channels for reports tied to the changed workflow.

Record the result in the release thread: “25% complete; synthetic checkout passed; no new checkout error pattern observed; proceeding.” This creates an operational audit trail without turning every release into bureaucracy.

9. Install the checklist this week and rehearse one rollback

Start with one service and one upcoming release. Add a pull-request template containing the release record fields: build ID, owner, approver, test links, rollout stages, dashboards, stop criteria, and rollback command. Keep the template in the repository so it changes alongside the system it governs.

Then schedule a 30-minute rollback rehearsal. Choose a harmless feature flag or a non-critical service, deploy a known change to staging, disable it, redeploy the previous artifact, and verify the old behavior. Note every manual credential request, missing dashboard, ambiguous command, or unclear ownership handoff.

The first rehearsal will expose the gap that generic release-management guidance tends to hide: rollback speed is usually constrained by access, artifact naming, database compatibility, and decision authority—not by the deploy button. Fix one of those constraints each release.

Finally, review the checklist after any rollback or significant incident. Remove checks that never influenced a decision, add the signal that would have caught the problem earlier, and keep the process small enough that engineers use it under pressure. A release process earns its place when it makes the next bad deployment smaller, shorter, and easier to reverse.