Post-Deploy Verification Checklists
Most teams have a post-deploy checklist, even if it is only in someone's head: open the home page, click through to a guide, try search, check that the new page is there. It is done carefully after big releases and skipped after small ones, which is exactly when the unexpected breakage happens — a header rule lost in a host configuration change, a redirect file that failed to upload, a noindex from a preview build that leaked into production. The checklist is valuable; the manual execution is not.
This guide turns a static documentation site's post-deploy checklist into an automated suite that runs against production after every deploy: version, key pages, redirects, headers, assets, search, forms, indexing directives and a performance sanity check. It separates hard failures that roll back automatically from soft ones that alert a person. It is part of Rollbacks and Deploy Safety for Static Sites, and extends Running Smoke Tests Against a Preview URL to production.
Prerequisites
- A production deploy step in CI, and a rollback command for the host (
wrangler rollback, Netlify's API to restore a deploy, or a blue-green switch). - The build's version stamped into the HTML, as in Tracking Deploy Markers in Analytics.
- Playwright and Node in CI.
Step 1: Write Down the Manual Checklist
The team's informal checklist, collected from three people who had done releases:
- The site loads and shows the new version.
- The home page, a guide, the API reference and the changelog load.
- Old URLs from the last migration still redirect.
- Security headers are present.
- Search returns results.
- The feedback form submits.
- The site is indexable (no stray
noindex) androbots.txtis right. - It "feels fast".
Each item became one or more automated checks, and two items that people had forgotten were added from past incidents: the sitemap is reachable and lists the new pages, and the 404 page returns a 404 status.
Step 2: Wait for the Deploy to Be Live
Checks that run before the new version is served test the old version and pass misleadingly. The suite first polls the version stamp until it matches the deployed commit, with a timeout:
async function waitForVersion(base, sha, timeoutMs = 180_000) {
const short = sha.slice(0, 7), start = Date.now();
while (Date.now() - start < timeoutMs) {
const html = await (await fetch(`${base}/?v=${Date.now()}`, { headers: { 'Cache-Control': 'no-cache' } })).text();
if (html.includes(`data-version="${short}"`)) return;
await new Promise((r) => setTimeout(r, 5000));
}
throw new Error(`production still not serving ${short} after ${timeoutMs / 1000}s`);
}
The cache-busting query parameter and no-cache header avoid reading a stale edge copy; the check still requests the canonical URL for everything else. A timeout here is itself a hard failure: the deploy did not take effect.
Step 3: The Checks
The suite is a single Node script plus one Playwright test file, organized by the checklist:
- Key pages: 25 URLs across templates, each must return 200, contain its expected
h1, and reference the current version's stylesheet. - Assets: every script, stylesheet and preload referenced from those 25 pages returns 200 with the right content type.
- Redirects: 40 cases sampled from the redirect map, including the oldest migration's URLs, via the table in Testing Redirects and Headers Before Deploy.
- Headers: CSP, HSTS,
X-Content-Type-Options, and cache headers on HTML and a hashed asset. - Indexing:
robots.txtallows crawling and points at the sitemap; no page among the 25 carriesnoindex; the sitemap returns 200 and contains the URLs of pages added in this deploy. - 404 behaviour: a random missing URL returns status 404 with the 404 page.
- Search: Playwright opens the search dialog, queries a known term and follows the first result.
- Form (soft): submits the feedback form in dry-run mode.
- Performance (soft): a single Lighthouse run of the home page and one guide, compared with the median of the last five deploys.
The whole suite ran in 74 seconds.
Step 4: Roll Back on Hard Failures
Hard failures mean readers are affected now. The workflow rolls back without waiting for a person, then alerts:
- name: Post-deploy verification
id: verify
run: node scripts/verify-production.mjs --base https://docs.example.com --sha $GITHUB_SHA
- name: Roll back on failure
if: failure() && steps.verify.outcome == 'failure'
run: |
npx wrangler rollback --message "auto-rollback: post-deploy verification failed for ${GITHUB_SHA::7}"
node scripts/notify.mjs --level page --text "Production rolled back: $(cat verify-report.txt | head -5)"
After a rollback, the suite runs again against the restored version, to confirm the rollback worked and that the failure was caused by the deploy rather than by something external. Soft failures — a Lighthouse score 15% below the recent median, a form dry run failing — post to the team channel with the report attached. How fast the rollback itself is depends on the host, as covered in Rolling Back a Bad Static Deploy in Under a Minute.
What It Caught
In the first year, across about 1,100 production deploys, the hard checks triggered six automatic rollbacks:
- A host configuration change that dropped the
_headersfile from the deploy: CSP and HSTS missing. - A preview-only
noindexheader rule that was accidentally applied to production. - A redirect file that exceeded the host's rule limit and was silently truncated; 31 old URLs returned 404.
- Two builds where a template error produced an empty
<main>on the API reference, which the pre-deploy snapshot test had not covered for that template. - A search index that failed to upload because of a file-size limit, leaving the new HTML pointing at missing index fragments.
Each would previously have been found by a reader, or by search traffic dropping. Soft checks flagged 14 performance regressions, of which 11 were real.
Keep the checklist and the suite in step: when an incident reveals a failure mode no check covered, the fix includes a new check, and the incident review records which check it is. Half of the current checks on this site were added that way.
Measured Impact
| Measure | Manual checklist | Automated verification |
|---|---|---|
| Deploys verified | ~20% (big releases) | 100% |
| Incidents reaching readers from bad deploys (per year) | 7 | 0 |
| Median time from bad deploy to rollback | 2 h 10 min | 2 min 40 s |
| Automatic rollbacks | — | 6 |
| Person-minutes per deploy | ~10 (when done) | 0 |
Pitfalls & Rollback
- Checking before the new version is live. Wait for the version stamp or the checks test the old site.
- Rolling back on soft signals. Lighthouse variance would cause needless rollbacks; alert instead.
- Checks that depend on third parties. Keep external services out of hard checks, or a vendor outage rolls back a good deploy.
- No re-check after rollback. Confirm the restored version passes, or you may be chasing an external failure.
- Rollback of the automation: the verification step can be switched to report-only by removing the rollback step.
Conclusion
A post-deploy checklist is only useful if it runs every time, and it only runs every time if a machine runs it. Turn each manual item into a check against the real production hostname, wait for the new version before checking, separate hard failures that roll back automatically from soft ones that alert, and re-verify after rolling back. On this site that verified every one of 1,100 deploys, rolled back six bad ones within minutes, and ended reader-facing incidents from deploys.
FAQ
What should be checked after deploying a static site?
That production serves the new version, that key pages load with the right content, that redirects and security headers are intact, that assets referenced by the HTML exist, that search and any forms work, that robots and indexing directives are correct, and that performance has not regressed sharply.
How is post-deploy verification different from pre-deploy tests?
Pre-deploy tests check the build and a preview. Post-deploy checks run against the real production hostname, through the real CDN configuration, custom domain, certificate and caching, which previews do not always share. They catch configuration and environment differences.
Should failures trigger an automatic rollback?
For checks that are deterministic and clearly mean the site is broken, such as the home page returning an error or the version not updating, yes. For softer signals, such as a slower Lighthouse score, alert a person instead of rolling back automatically.
How long should the checks take?
Short enough to run on every deploy without delaying the next one, typically one to three minutes. The suite here ran in 74 seconds, with slower checks such as a full link crawl scheduled separately.
Related
- Parent: Rollbacks and Deploy Safety for Static Sites — safe deployment practices.
- Running Smoke Tests Against a Preview URL — the same checks before merge.
- Blue-Green Deploys for Static Sites — verifying before the switch.
- Uptime and Synthetic Checks for Static Sites — continuous checks between deploys.
- Testing Static Sites in CI — the pre-deploy suite.
Filed underHow-tos