Firebase Hosting Go-Live Checklist (10 Steps)

A reproducible 10-step pre-launch checklist for Firebase Hosting (June 2026): firebase.json, custom-domain DNS, SSL timing, cache headers, redirects, sitemap, and a rehearsed rollback.

You are about to point your real domain at Firebase Hosting. The site works in dev, it works on *.web.app. The risky moment is the DNS switch: do it wrong on a Friday and you spend the weekend watching Search Console flag duplicate URLs and a half-issued SSL cert. Run these 10 checks first. Every one is something an indie dev has been bitten by at least once.

TL;DR

  • Match firebase.json’s public to your real build folder (dist for Astro/Vite, out for a Next static export), and lock cache headers before you deploy.
  • Pick one canonical host (apex or www) and 301 the other. Both indexed = split crawl budget.
  • Wait for the custom-domain SSL cert before flipping DNS. Provisioning takes up to 24 hours (usually a few hours) per Firebase docs.
  • Submit the sitemap to Search Console on the canonical domain only — never *.web.app, never apex + www both.
  • Rehearse a rollback so it is muscle memory: Hosting → Release history → Rollback. Downtime is typically under a minute.

The 10-step checklist

1. Confirm firebase.json matches your build folder and locks cache headers

For Astro the build folder is dist, a Next static export is out, Vite is dist. Ship this config for a static content site — fingerprinted assets get a one-year immutable cache, HTML gets a short browser TTL with a longer CDN TTL plus stale-while-revalidate so visitors almost never wait on a cache miss:

{
  "hosting": {
    "site": "your-firebase-project",
    "public": "dist",
    "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
    "cleanUrls": true,
    "trailingSlash": true,
    "redirects": [
      { "source": "/blog/:slug", "destination": "/articles/:slug", "type": 301 }
    ],
    "headers": [
      {
        "source": "/_astro/**",
        "headers": [
          { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }
        ]
      },
      {
        "source": "**/*.@(html)",
        "headers": [
          { "key": "Cache-Control", "value": "public, max-age=300, s-maxage=3600, stale-while-revalidate=86400" }
        ]
      },
      {
        "source": "**",
        "headers": [
          { "key": "X-Content-Type-Options", "value": "nosniff" },
          { "key": "Referrer-Policy",        "value": "strict-origin-when-cross-origin" }
        ]
      }
    ]
  }
}

cleanUrls: true drops the .html extension and 301s any request that still includes it. trailingSlash: true makes Hosting redirect to add a trailing slash, so your canonical shape is consistent. The immutable directive on hashed assets skips the revalidation round trip entirely.

2. Decide your canonical host: apex or www

Add both in Firebase Console → Hosting → Add custom domain, then set the non-canonical one to redirect. The Firebase wizard prints the exact A-record IP for your domain (199.36.158.100 as of June 2026); use whatever the console shows you. A typical apex-primary setup:

Type   Name        Value
A      @           199.36.158.100
CNAME  www         your-project.web.app

If you are migrating a domain that already gets traffic, use Advanced Setup instead of Quick Setup. Advanced Setup verifies ownership and provisions the cert before you repoint DNS, so Hosting is ready to serve the right content the instant traffic arrives — that is your zero-downtime path.

3. Confirm SSL on both hostnames before flipping traffic

Per Firebase, cert provisioning can take up to 24 hours after DNS points at Hosting (usually a few hours). Verify it issued before you cut over:

curl -vI https://yourdomain.com 2>&1 | grep -E 'subject:|issuer:|HTTP'
# subject: CN=yourdomain.com
# issuer: C=US, O=Google Trust Services LLC, CN=...
# HTTP/2 200

If you see subject: CN=*.web.app, the custom-domain cert has not been issued yet — wait, do not flip DNS.

4. Test trailing-slash and clean-URL behavior

In incognito, hit several path shapes and check the status codes match your firebase.json rules:

curl -sI https://yourdomain.com/about    | head -1   # expect 301 → /about/
curl -sI https://yourdomain.com/about/   | head -1   # expect 200
curl -sI https://yourdomain.com/missing/ | head -1   # expect 404, NOT 200

A 200 on /missing/ means a catch-all rewrite is masking real 404s, which lets Google index junk URLs.

5. Run Lighthouse on the live URL

Aim for Performance and Best Practices above 90 — static Firebase Hosting on Google’s CDN makes this easy to hit:

npx lighthouse https://yourdomain.com/ \
  --only-categories=performance,best-practices,seo \
  --chrome-flags="--headless" --quiet

6. Submit the sitemap to Search Console on the canonical domain only

Never the *.web.app URL, and never both apex and www:

Search Console → Sitemaps → Add a new sitemap
URL: https://yourdomain.com/sitemap-index.xml

7. Set canonical and og:url to the production domain

A stray *.web.app or staging URL in your <link rel="canonical"> or Open Graph tags will quietly de-index the real domain. Scan the build output:

grep -ROIE 'rel="canonical"|og:url' dist | grep -v yourdomain.com | head
# any output = wrong domain leaked into the HTML

8. Rehearse a rollback before you need one

Firebase keeps prior releases in Hosting storage (you can cap how many under Release storage settings). Practice the rollback now so it is reflex during an incident:

firebase hosting:releases:list
# release-1 (current)  2026-05-22 14:02  abc123
# release-0            2026-05-22 13:40  def456

firebase deploy --only hosting    # each deploy creates a new release
# Console: Hosting → Release history → ⋮ → Rollback

Rolling back creates a new release serving the previous version’s content — it does not delete anything, so it is always safe to try.

9. Set budget alerts (Blaze users)

Hosting on the free Spark plan includes 10 GB storage and 360 MB/day of transfer, and commercial use is allowed. On Blaze (pay-as-you-go), the same free quota applies, then bandwidth is roughly $0.20/GiB and storage $0.10/GB. In GCP Console → Billing → Budgets & alerts, set alerts at 50% and 90% of expected spend. For pure static hosting this should rarely fire — but a runaway script or hotlinked assets can surprise you.

10. Final pre-flip checks against the *.web.app URL

Run these before you switch DNS, while the site is still only on *.web.app:

curl -s https://your-project.web.app/sitemap-index.xml | grep -c '<loc>'
curl -s https://your-project.web.app/robots.txt | head
curl -sI https://your-project.web.app/         | grep -i cache-control

If the URL count looks right, robots.txt references your sitemap, and the cache header matches step 1, you are clear to point DNS.

Quick reference: timings and limits (June 2026)

ItemWhat to expect
SSL cert provisioningUp to 24h after DNS points at Hosting; usually a few hours
DNS propagation5-30 min for most users if you lowered TTL beforehand; up to 24h fully
Spark free tier10 GB storage, 360 MB/day transfer, commercial use allowed
Blaze overage~$0.20/GiB bandwidth, ~$0.10/GB storage above the free quota
Rollback downtimeTypically under a minute
Released versions keptConfigurable via Release storage settings

Common pitfalls

  • Skipping the canonical decision and ending up with both apex and www indexed in Google.
  • Submitting the sitemap on a non-canonical domain — wasted crawl budget.
  • Forgetting to update og:url when switching to a new domain.
  • Flipping DNS before the custom-domain SSL cert has issued, serving cert warnings to first visitors.
  • Going live on a Friday without a tested rollback.
  • Leaving a *.web.app or staging URL in any sitemap or canonical tag.

If you have not yet pointed a real domain and are still on a preview channel, only steps 1-5 apply — the rest are about the DNS cutover.

FAQ

  • How long before traffic stabilizes after switching DNS? Most of the world is on the new host within 5-30 minutes if you lowered TTL beforehand. Full propagation can take up to 24 hours.
  • Why does my domain still serve the old cert or a *.web.app warning? The custom-domain certificate has not finished provisioning. Firebase says this can take up to 24 hours after DNS points at Hosting, though it is usually a few hours. Wait and re-run the curl -vI check in step 3 before cutting traffic over.
  • Should I disable the *.web.app URL after launch? You cannot disable it, but setting canonical tags and og:url to the custom domain stops search and social from picking up *.web.app.
  • Do I need a robots.txt? Yes. Even a permissive one with just a sitemap reference helps crawlers find your sitemap fast.
  • What if I find a critical bug right after going live? Hosting → Release history → Rollback to the previous release, then fix and redeploy. Rollback creates a new release from old content and total downtime is usually under a minute.
  • Apex or www — which is the safer canonical? Either works. Apex (yourdomain.com) looks cleaner in the SERP; www is slightly easier to put behind a third-party CDN later. The only wrong answer is indexing both.

Tags: #Indie dev #Firebase #Hosting #Workflow #SEO