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’spublicto your real build folder (distfor Astro/Vite,outfor 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 +wwwboth. - 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)
| Item | What to expect |
|---|---|
| SSL cert provisioning | Up to 24h after DNS points at Hosting; usually a few hours |
| DNS propagation | 5-30 min for most users if you lowered TTL beforehand; up to 24h fully |
| Spark free tier | 10 GB storage, 360 MB/day transfer, commercial use allowed |
| Blaze overage | ~$0.20/GiB bandwidth, ~$0.10/GB storage above the free quota |
| Rollback downtime | Typically under a minute |
| Released versions kept | Configurable via Release storage settings |
Common pitfalls
- Skipping the canonical decision and ending up with both apex and
wwwindexed in Google. - Submitting the sitemap on a non-canonical domain — wasted crawl budget.
- Forgetting to update
og:urlwhen 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.appor 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.appwarning? 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 thecurl -vIcheck in step 3 before cutting traffic over. - Should I disable the
*.web.appURL after launch? You cannot disable it, but setting canonical tags andog:urlto 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 → Rollbackto 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;wwwis slightly easier to put behind a third-party CDN later. The only wrong answer is indexing both.
Related
- Deploy a static site to Firebase Hosting step-by-step
- Connecting a custom domain to Firebase Hosting
- Submit website to Google
- Firebase Hosting custom-domain docs (official)
Tags: #Indie dev #Firebase #Hosting #Workflow #SEO