When Is a Deployment Really Finished?
You just ran your deployment command. The terminal shows a clean green output. No errors. No warnings. The new container is running. The files are in place. Your team starts packing up to go home.
But is the deployment actually done?
Most teams treat the moment the deploy command finishes as the finish line. That is a dangerous assumption. What you know at that point is only that the process of moving files or restarting services completed successfully. You do not yet know whether the application is actually working.
The Difference Between Deploying and Being Healthy
A deployment has two distinct phases. The first is the technical act of putting the new version into place. The second is verifying that the new version behaves correctly. Many teams stop after phase one and call it a day.
The following flowchart illustrates the two-phase process described above:
Think about what can go wrong after a successful deploy:
- The new code has a configuration error that only shows up under real traffic
- A database migration succeeded but the application code expects a different column name
- A dependency was updated and broke an integration that unit tests did not catch
- The new version uses more memory and triggers an OOM killer after a few minutes
None of these would show up in your deployment logs. The terminal would still say "deploy successful." But the application would be broken.
What Counts as Evidence
A deployment is only finished when you have evidence that the new version is healthy and ready to serve users. That evidence must be measurable and verifiable. Gut feelings and "looks fine to me" do not count.
The evidence comes from multiple sources. Smoke tests are the most basic layer. They check that the application starts, the main page loads, and core features respond. A smoke test that fails means something fundamental is wrong.
Here is a minimal script that automates the first layer of evidence collection after a deployment:
#!/bin/bash
# post-deploy-verify.sh - Run after deploy command
set -euo pipefail
URL="https://your-app.example.com"
DB_CONN_STRING="postgresql://user:pass@db-host:5432/app"
# 1. Health check
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$URL/health")
if [ "$HTTP_CODE" -ne 200 ]; then
echo "FAIL: Health check returned $HTTP_CODE"
exit 1
fi
echo "PASS: Health check returned 200"
# 2. Smoke test - main page loads
if ! curl -s "$URL" | grep -q "<title>App</title>"; then
echo "FAIL: Main page missing expected title"
exit 1
fi
echo "PASS: Main page loads correctly"
# 3. Database connectivity test
if ! psql "$DB_CONN_STRING" -c "SELECT 1" > /dev/null 2>&1; then
echo "FAIL: Database connection failed"
exit 1
fi
echo "PASS: Database connection successful"
echo "All checks passed - deployment evidence collected"
Synthetic transactions go deeper. They simulate real user flows: logging in, searching for data, submitting a form, checking out an order. If a synthetic transaction passes, you know that a complete user journey works end to end.
Then there are the system signals we discussed earlier in this series. After deployment, you need to check whether availability stays stable, error rates do not spike, and latency does not degrade. If all these signals look normal, you have a strong case that the new version is not causing problems.
The Trap of Casual Verification
The real danger is not that teams skip verification entirely. It is that they do it casually. A developer glances at a dashboard, sees green bars, and assumes everything is fine. But that glance might miss a subtle increase in 500 errors. It might miss that the checkout flow is timing out for a subset of users.
Casual verification fails because it relies on human attention and memory. The developer who deployed might be tired after a long day. They might be in a hurry to join another meeting. They might not know exactly which signals to check for this particular change.
The solution is to define your evidence criteria before you deploy. Decide in advance what signals will prove that the deployment is complete. Write them down. Make them explicit.
A reasonable set of criteria might look like this:
- Smoke test for the main page and login flow passes
- Synthetic transactions for the three most critical user journeys pass
- Error rate stays below 0.1 percent
- P95 latency does not increase more than 5 percent from the pre-deployment baseline
- Database connection pool utilization stays below 70 percent
When all these conditions are met, the deployment is done. If any condition fails, the deployment is not done, even if the deploy command succeeded.
Who Decides the Deployment Is Complete
In a small team, the developer who deployed often makes the call. They check the criteria, verify the signals, and decide whether to call it done. This works when the team is small and everyone knows the system well.
As the team grows, the decision should shift to automation. The pipeline itself should not mark the deployment as complete until all automated checks pass. This removes human judgment from the loop and ensures consistency. Every deployment gets the same verification, every time.
For high-risk changes, you might still want a human in the loop. A senior engineer or an on-call person can review the evidence and make a final call. But even then, the criteria should be clear. The human is not guessing whether things look okay. They are checking a predefined list of conditions.
There is no universal rule for how much evidence is enough. A minor bug fix to an internal tool needs less verification than a major feature change to a customer-facing payment system. The important thing is that your team agrees on the criteria for each type of change.
A Practical Checklist for Deployment Completion
Here is a simple checklist you can adapt for your team:
- Deployment command completed without errors
- Smoke tests passed (main page, login, core features)
- Synthetic transactions passed (critical user journeys)
- Error rate within acceptable range
- Latency within acceptable range
- Resource usage (CPU, memory, connections) stable
- No alerts triggered from monitoring systems
- Database migrations applied and verified
If any item fails, the deployment is not complete. Investigate before declaring success.
What Changes When You Get This Right
When your team agrees that deployment is not finished until there is evidence of health, the entire deployment process shifts. Deployment stops being a technical task that ends at the terminal. It becomes a transition that ends when users can safely use the new version.
This shift changes behavior. Teams start writing better smoke tests because they know those tests determine whether they can call it a day. They start defining clear criteria before deploying, not after. They stop rushing to close the deployment and start paying attention to what happens after the new version goes live.
The next time your team runs a deployment, watch what happens after the command finishes. Does everyone relax and move on? Or do they check the evidence first? That moment tells you whether your team truly understands when a deployment is done.