Skip to main content
ASoc
Guide

A Website Launch Checklist Where Every Item Is a Command

Five commands, three greps, and the defects they caught on a site that already looked finished — including a licence page selling a tier that no longer existed.

The ASoc Team11 min read

A checklist you read is a checklist you skip. The useful version is executable: five commands that fail the pipeline, plus a short list of greps that fail a human. Every item below is on ours because it once caught something real — a nav menu whose five links all pointed at one URL, two products sharing a byte-identical cover image, a licence page still selling a tier that had been renamed months earlier.

This is the pre-deploy pass for a site that already exists and already looks right. It assumes the design is chosen and the content is written. What it checks is whether the thing you are about to publish is true: that its links resolve, its claims match its code, its images are the images you think they are, and its secrets are not in the bundle.

The five commands

Everything here runs on every push and every pull request, on Node 22, with a fifteen-minute ceiling:

CommandFails onWhy it earns a slot
npm ciA lockfile that does not match package.jsonThe one install that reproduces what CI and production get
npm run lintESLint errors, including framework rulesCatches raw <a> to internal routes, missing keys, unsafe patterns
npm run format:checkUnformatted filesKeeps diffs about content, not whitespace
npm testA failed invariantWhere the content checks live — see below
npm run buildA type error or a page that cannot renderThe only check that renders every page

The build is the heaviest and the least negotiable. It type-checks every component and prerenders every route, which means a broken data reference in one of 111 product pages fails the pipeline instead of returning a 500 to whoever clicks it first. Our latest run prerendered 256 pages and left 8 routes dynamic — the API handlers, the auth callback and the account pages. If your build output shows routes you expected to be static rendering per request, fix that before launch; the four things that force a route dynamic are all small and all cheap to undo at this stage.

The tests that check content, not components

Most of what breaks a launch is not logic. It is a reference to something that no longer exists. So the test suite spends most of its assertions on the content graph:

  • Every catalog product resolves its own files. If an entry names a screenshot, the file must exist under public/. A renamed directory becomes a red test rather than a broken card.
  • Every blog post exists in three places. Metadata registry, MDX file, and an explicit loader entry. Miss one and the suite fails; a wildcard import would have turned that into a runtime 404.
  • Every in-post link target exists. Posts declare the products and category hubs they point at, and those declarations are verified against the catalog. A retired product cannot leave a dead link in a published article.
  • Every available product appears on at least one category hub. This one is the reason it exists: hand-listed hubs silently stopped covering new products, and 24 of them ended up on no hub at all.

The pattern generalises past this codebase. Anything you would otherwise verify by clicking — does this page link to that page, does this image exist, does this list still cover everything — is a test, and it costs about ten lines.

The greps that are not tests yet

Three sweeps run by hand before a deploy. Naming them here is also an admission: they should be CI steps, and they are not.

# 1. No placeholder links anywhere in the source.
grep -rn 'href="#"' src/

# 2. No trace of the source template's brand in the shipped site.
grep -rni '<original-vendor-name>' src/ public/

# 3. No wrong-domain internal links.
grep -rn 'https://.*\.example\.com' src/

The first is the one that matters most and the one people skip. A placeholder anchor renders as a link, passes every visual review, and does nothing when clicked. Our rule is zero of them in the tree — not "few", zero — because a threshold above zero cannot be checked automatically.

The second exists because this site started as a port. Anything you build from a template, a starter or an agency handover carries the previous owner's strings in places no design review looks: alt text, JSON-LD, manifest fields, comments in shipped CSS.

What ours actually caught

Not hypotheticals. These are the defects the passes above found on a site that looked finished:

Found byDefect
Link sweepA products mega-menu whose five per-framework tiles all pointed at the same product URL
Link sweepThree nav items pointing at pages that did not exist, all silently dumping users on /docs
Copy auditA "V 2.3" version chip on a product whose catalog version was 1.0.0
Copy auditA GitHub button showing ... where a star count belonged, leaving the link with no accessible name
Image auditTwo products sharing a byte-identical cover (same md5) — one of them was showing the wrong product
Image auditTwo cover.png files that were actually JPEGs; format and extension disagreed
Cross-page read/pricing selling Single $39 / All-Access $129 / Full Stack $249 while /license still described a "Studio ($149)" tier that no longer existed
Accessibility passA page with no h1; another skipping h1h3; a tag chip at 4.49:1 against a 4.5:1 requirement

The pricing-versus-licence mismatch is the instructive one. No linter finds it. No test finds it, because both pages were internally consistent. It was found by reading the two pages side by side and asking whether a buyer comparing them would see the same offer twice. Budget an hour for that read; it is the highest-yield hour in the whole checklist.

Secrets, before anyone can fetch them

Two checks, both mechanical:

# Nothing secret-shaped in the git history.
gitleaks detect --config .gitleaks.toml

# Nothing secret-shaped in what the browser downloads.
grep -rl "$YOUR_SECRET_VALUE" .next/static

The second is the one people never run, and it takes a second. Build with your real environment, then grep the built client bundle for the value of each secret. We ran exactly that with marker values in place of the real ones: both public variables landed in one client chunk each, and all three server-only secrets landed in zero. The measurement, and the build-time-versus-run-time trap behind it, is its own post.

Gitleaks needs an allowlist or it will flag your own .env.example. Ours permits obvious placeholder shapes (re_xxxx…, your-api-key, changeme) only in files matching .env.{example,sample,template} — narrow enough that a real key in a real file still trips it.

Crawl, index and the claims you make to Google

The launch is where SEO mistakes get baked in, because they take weeks to surface and longer to unwind:

  • Ship robots.txt and a sitemap, and make the sitemap honest. lastModified must be a real content date, never the build clock. Telling a search engine that 250 URLs changed on every deploy is a checkable false claim, and it costs the crawl scheduling that decides whether a page gets indexed at all.
  • Check the internal link graph, not just the page count. We put 38 product pages into "Discovered — currently not indexed" by generating pages that nothing linked to. The whole story is in the programmatic-SEO post; the short version is that a page with no inbound links is a page you told nobody about.
  • Canonicals and metadata on every route. Including the ones added late — the pages that ship after the launch audit are exactly the pages the launch audit never saw.
  • Decide what is indexable before it is live. Facet and filter URLs, staging subdomains, preview deployments. A noindex you leave on for months eventually stops being crawled at all, which means the day you remove it nothing happens.

Security headers belong in the same pass, and they are one config block: a content-security policy, X-Content-Type-Options, Referrer-Policy, X-Frame-Options and HSTS. Add preload to HSTS after launch, once every subdomain is confirmed HTTPS-only — it is hard to reverse.

Mistakes and how they show up

MistakeSymptomFix
Checklist as a documentSkipped under deadlineMake each item a command that fails the build
Testing components, not contentGreen suite, broken linksAssert that referenced files and routes exist
href="#" tolerated "for now"Dead clicks nobody reportsEnforce zero, by grep, in the pipeline
Never grepping the client bundleA secret ships and stays in a cached buildGrep .next/static for each secret value
lastModified: new Date()Sitemap claims everything changed; crawl budget wastedDerive it from real content dates
Pages with no inbound links"Discovered — currently not indexed"Fix the link graph, not the sitemap
Launch-day accessibility check onlyPages added later skip the audit entirelyRe-run the sweep over every route, not the original set
Trusting file extensionsFormat and extension disagree; some clients refuse the imageVerify by content, not by name
Two pages describing the same offerBuyer sees two prices, trusts neitherRead the money pages side by side, by hand

Frequently asked questions

How long should a pre-launch pass take? The automated part should be minutes, because it is CI. The human part — reading the money pages against each other, clicking through the primary nav, checking the images are of the right products — is a couple of hours for a site of this size. If it takes a day, most of that day belongs in a test.

Is a staging environment required? A preview deployment per pull request covers most of the value: a real URL, real headers, real build output, no shared state to corrupt. What a preview does not give you is production data or production DNS, which is why the first hour after go-live is part of the checklist too.

What about backups and rollback? For a statically-rendered marketing site the rollback is the previous deployment, and it is instant. What actually needs a backup plan is anything with a database behind it: know, before launch, how you would restore and how much data you would lose.

Do I need all of this for a five-page site? The commands, yes — they cost nothing once configured. The content-graph tests scale with how much content you have; at five pages, reading them is faster than testing them. The break-even is somewhere around the point where you stop being able to click every page in one sitting.

We bought a template. Does that change the list? It adds one item: sweep for the original vendor's branding and demo content everywhere, including metadata and image alt text. And it removes almost none of the others — a template ships a site, not a launch.

Templates that ship launch-ready

Every template below arrives with the parts this checklist tests: real routes rather than placeholder anchors, per-page metadata, a sitemap and robots file, and an accessible, measured baseline. The three here are the ones whose own subject matter is uptime, analytics and search visibility — which is what you are about to start caring about.

Keep reading

Guide8 min read

Website Template Copyright: What You Own, What You Don't

Buying a template never transfers copyright in its code. What you actually own, plus the hardcoded footer year this codebase shipped unfixed for a month.

Read more