Firebase Hosting is excellent for static Next.js exports — global CDN, automatic HTTPS, generous free tier, and preview channels built in. Here is the CI/CD setup we use across our client projects.
The Pipeline
Our GitHub Actions workflow has three jobs: build, preview (on PRs), and deploy (on main).
Build job: Install dependencies, run next build, upload the out/ directory as an artifact. We cache the Next.js build cache and node_modules using actions/cache to keep build times under 2 minutes.
Preview job: On every pull request, deploy to a Firebase Hosting preview channel with a unique URL. This gives every PR its own live URL — reviewers can test on mobile without running the project locally. Preview channels auto-expire after 7 days.
Deploy job: On merge to main, deploy to the live channel. Firebase Hosting deploys are atomic — the CDN is updated globally within 30 seconds, and if the deploy fails partway through, the old version continues serving. This is the zero-downtime guarantee.
Lighthouse in CI
We run Lighthouse CI on every deploy and fail the pipeline if Performance drops below 85, Accessibility below 90, or SEO below 90. This catches regressions before they reach production.
The Lighthouse CI configuration runs against the preview channel URL, so it tests the real deployment, not a local build. We store historical Lighthouse scores in a private LHCI server to track trends over time.
Firebase Configuration
Two things that trip people up: cleanUrls: true removes the .html extension so /about.html is served as /about. And the catch-all rewrite must come last in the rewrites array, after all specific route rules, or Firebase serves index.html for routes that have their own HTML files.
This setup has run in production for 15+ client projects with zero downtime incidents.