What is Firebase Hosting (and who is it for in 2026)

Firebase Hosting is Google's static + edge CDN service tied to Firebase. Here is when it fits, with the firebase.json baseline and deploy commands.

Firebase Hosting is the static-and-edge layer of Google’s Firebase platform. It serves files from a global CDN, gives you free SSL, and plugs into the rest of Firebase — Auth, Firestore, Cloud Functions. It is not a Next.js host in the Vercel sense, and treating it like one is where most beginners get burned. Below is the right mental model, the baseline firebase.json, and the commands to go from zero to live.

Background

Firebase Hosting launched in 2016 and has gradually grown from “static files only” to “static + dynamic rewrites to Cloud Functions / Cloud Run”. In 2026 it sits in an awkward middle: more capable than pure object storage, less capable than a framework-native platform. The right mental model is “a CDN that knows how to call your backend”, not “a Next.js runtime”.

How to tell

  • You already use Firebase Auth, Firestore, or Cloud Functions and want one bill.
  • Your site is static HTML / a SPA / an Astro static build — not a heavy SSR app.
  • You want free SSL and a global CDN without configuring anything.
  • You need preview channels for sharing branches with clients.
  • You do not need server-side rendering at the edge of every request.

Quick verdict

Use Firebase Hosting when the rest of your stack is already Firebase, or when your site is mostly static. Skip it when you want zero-config Next.js SSR — Vercel is built for that.

Before you start

  • A Firebase project (create via console or firebase projects:create).
  • Node and firebase-tools installed (npm install -g firebase-tools).
  • Static build output ready (dist/, out/, build/).

Step by step

  1. Confirm the output is static. A directory with index.html, asset folders, and per-route subdirectories. If your output is a Node server (Next.js SSR without static export), reconsider Firebase Hosting.

  2. Install and authenticate the CLI:

npm install -g firebase-tools
firebase login
firebase projects:list
  1. Initialize hosting in the project:
firebase init hosting
# ? Public directory? dist
# ? Configure as a single-page app? No   (static sites/Astro: No)
# ? Set up automatic builds and deploys with GitHub? (optional)
  1. Baseline firebase.json for a static content site:
{
  "hosting": {
    "public": "dist",
    "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
    "cleanUrls": true,
    "trailingSlash": true,
    "headers": [
      {
        "source": "/_astro/**",
        "headers": [
          { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }
        ]
      },
      {
        "source": "**/*.html",
        "headers": [
          { "key": "Cache-Control", "value": "no-cache, max-age=0" }
        ]
      },
      {
        "source": "**/*.@(jpg|jpeg|png|webp|avif|svg|woff2)",
        "headers": [
          { "key": "Cache-Control", "value": "public, max-age=2592000" }
        ]
      }
    ]
  }
}
  1. Decide on rewrites:
{
  "hosting": {
    "rewrites": [
      { "source": "/api/**", "function": "api" },
      { "source": "/render/**", "run": { "serviceId": "ssr-render", "region": "us-central1" } }
    ]
  }
}

For SPAs that need an index.html fallback only, use the ** → /index.html rewrite — but never for content sites, where it breaks real 404s.

  1. Build and deploy:
npm run build
firebase deploy --only hosting
# Hosting URL: https://your-project.web.app
  1. Test in incognito + curl:
curl -sI https://your-project.web.app/ | grep -i cache-control
curl -sI https://your-project.web.app/this-does-not-exist/ | head -1
# expect HTTP/2 404 (not 200)
  1. Add a custom domain. Firebase Console → Hosting → Add custom domain → follow DNS prompts (typically two A records to Firebase’s anycast IPs and a CNAME for www). SSL is automatic.

Implementation checklist

  • public matches the framework’s output directory.
  • Cache headers explicit for HTML vs hashed assets.
  • No accidental ** rewrite to /index.html on a content site.
  • Custom domain green check + SSL valid.
  • Deploy releases tracked (Hosting → Release history).

After-launch verification

  • curl -sI shows expected cache headers.
  • A deliberate 404 returns HTTP 404, not 200.
  • The *.web.app URL and custom domain both serve identical content.
  • Preview channel via firebase hosting:channel:deploy produces a shareable URL.

Common pitfalls

  • Treating Firebase Hosting as a Next.js host — SSR support exists via Cloud Functions but is not as smooth as Vercel.
  • Forgetting to set cleanUrls / trailing slash behavior, then chasing 404s after deploy.
  • Leaving the default cache (1 hour) on HTML pages and wondering why updates do not show up.
  • Deploying the wrong public directory — usually the source folder instead of the build output.
  • Adding a SPA catch-all rewrite by accident — every URL returns the homepage.

FAQ

  • Is Firebase Hosting free?: There is a generous Spark (free) tier with 10 GB storage and 360 MB/day transfer. Plenty for most indie sites.
  • Does Firebase Hosting do SSR?: Indirectly, by rewriting requests to a Cloud Function or Cloud Run. It is not a first-class runtime like Vercel.
  • Can I use Firebase Hosting without other Firebase services?: Yes. You can host a plain static site with no Auth, Firestore, or Functions. Most people who do this eventually wish they had picked something framework-native instead.
  • Do I get HTTPS automatically?: Yes. Both the default *.web.app URL and custom domains get free SSL through Let’s Encrypt.
  • How do I roll back a bad deploy?: Firebase Hosting keeps release history. firebase hosting:clone or use the console’s Rollback button.

Tags: #Indie dev #Firebase #Hosting #Getting started