How to Deploy a Jekyll Site to Firebase Hosting (2026 Guide)
Deploy Jekyll to Firebase Hosting — complete setup with the Firebase CLI, firebase.json config, custom domains, URL rewrites, and GitHub Actions automation.
Firebase Hosting is Google’s static hosting platform — part of the Firebase suite alongside Firestore, Auth, and Cloud Functions. For a Jekyll site, it offers a fast global CDN, free SSL, a generous free tier, and seamless integration if you are already using other Firebase services. Here is how to set it up.
Why Firebase Hosting for Jekyll
- Free tier — 10GB storage, 10GB/month transfer (Spark plan), unlimited for pay-as-you-go
- Fast global CDN — Google’s infrastructure, same network used by Google’s own products
- Instant rollbacks — every deployment is versioned; roll back to any previous version in one click
- Preview channels — deploy to temporary preview URLs before going live
- Firebase integration — pair your Jekyll site with Firestore, Auth, or Cloud Functions if needed
- Custom domain + SSL — free certificate provisioning
Prerequisites
- A Jekyll site with a
Gemfileand committedGemfile.lock - Node.js installed (required for the Firebase CLI)
- A Firebase account (free at firebase.google.com, uses your Google account)
- A Firebase project created in the Firebase console
Step 1: Create a Firebase project
- Go to console.firebase.google.com
- Click Add project
- Enter a project name (e.g.
jekyllhub) - Disable Google Analytics if you do not need it (you can add it later)
- Click Create project
Step 2: Install the Firebase CLI
npm install -g firebase-tools
Verify the installation:
firebase --version
Log in:
firebase login
This opens a browser for Google OAuth authentication.
Step 3: Initialise Firebase in your Jekyll project
In your Jekyll project root:
firebase init hosting
The CLI walks you through setup:
? Which Firebase project do you want to associate with this directory?
> Use an existing project
> jekyllhub (jekyllhub)
? What do you want to use as your public directory?
> _site
? Configure as a single-page app (rewrite all urls to /index.html)?
> No
? Set up automatic builds and deploys with GitHub?
> No (we will set this up manually later)
? File _site/404.html already exists. Overwrite?
> No
This creates two files: firebase.json and .firebaserc.
Step 4: Configure firebase.json
The generated firebase.json is a starting point. Customise it:
{
"hosting": {
"public": "_site",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"cleanUrls": true,
"trailingSlash": true,
"headers": [
{
"source": "/assets/**",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000, immutable"
}
]
},
{
"source": "**/*.html",
"headers": [
{
"key": "Cache-Control",
"value": "no-cache"
},
{
"key": "X-Content-Type-Options",
"value": "nosniff"
},
{
"key": "X-Frame-Options",
"value": "DENY"
}
]
}
],
"redirects": [
{
"source": "/old-post/",
"destination": "/new-post/",
"type": 301
}
],
"rewrites": [
{
"source": "**",
"destination": "/404.html"
}
]
}
}
Key settings explained:
cleanUrls: true— serves/about/index.htmlwhen someone visits/aboutor/about/trailingSlash: true— adds trailing slashes to URLs (matches Jekyll’s default URL structure)headers— sets HTTP headers per file pattern (long cache for assets, no-cache for HTML)redirects— 301 or 302 redirects processed at the CDNrewrites— the catch-all to404.htmlhandles unknown URLs
Step 5: Build and deploy
Build your Jekyll site:
JEKYLL_ENV=production bundle exec jekyll build
Deploy to Firebase:
firebase deploy --only hosting
Firebase uploads _site/ to its CDN and gives you a live URL:
✔ Deploy complete!
Project Console: https://console.firebase.google.com/project/jekyllhub/overview
Hosting URL: https://jekyllhub.web.app
Your site is immediately live at your-project.web.app and your-project.firebaseapp.com.
Step 6: Add a custom domain
- In the Firebase console, go to Hosting → Add custom domain
- Enter your domain (e.g.
jekyllhub.com) - Firebase shows DNS records to add:
- Two A records for the root domain pointing to Firebase’s IP addresses
- A CNAME for
wwwpointing toyour-project.web.app
- Add these records at your domain registrar
- Firebase provisions an SSL certificate automatically once DNS propagates
You can add multiple custom domains at no charge on both the Spark (free) and Blaze (pay-as-you-go) plans.
Step 7: Use preview channels
Firebase preview channels let you deploy to a temporary URL for review before going live — similar to Netlify’s deploy previews:
# Deploy to a named preview channel
firebase hosting:channel:deploy staging
# Output:
# ✔ hosting:jekyllhub:staging: Channel URL (expires 7 days): https://jekyllhub--staging-abc123.web.app
Preview channels expire after 7 days by default. Useful for reviewing design changes before merging to main.
# List active channels
firebase hosting:channel:list
# Delete a channel when done
firebase hosting:channel:delete staging
Step 8: Instant rollback
Every Firebase deployment is stored as a versioned release. Roll back to a previous version instantly:
- Firebase console → Hosting → Release history
- Find the release you want to restore
- Click ⋮ → Rollback to this release
The rollback is instant — Firebase just updates its CDN pointers to the previous build.
Or via CLI:
firebase hosting:clone jekyllhub:live jekyllhub:live --version=VERSION_ID
Automate with GitHub Actions
# .github/workflows/deploy.yml
name: Deploy Jekyll to Firebase
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: "3.2"
bundler-cache: true
- name: Build Jekyll
run: JEKYLL_ENV=production bundle exec jekyll build
- name: Deploy to Firebase (production)
if: github.ref == 'refs/heads/main'
uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: "${{ secrets.GITHUB_TOKEN }}"
firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT }}"
channelId: live
projectId: jekyllhub
- name: Deploy PR preview
if: github.event_name == 'pull_request'
uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: "${{ secrets.GITHUB_TOKEN }}"
firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT }}"
projectId: jekyllhub
# No channelId = creates a preview channel automatically
Generate a Firebase service account
- Firebase console → Project settings → Service accounts
- Click Generate new private key → Download the JSON file
- Add the entire JSON as a GitHub secret named
FIREBASE_SERVICE_ACCOUNT
The GitHub Actions workflow then posts a comment on each PR with the preview URL — the same experience as Netlify deploy previews.
Using rewrites for dynamic routes
If you want to add Firebase Cloud Functions alongside your Jekyll static site (for example, a contact form handler or a newsletter API endpoint), use rewrites:
{
"hosting": {
"public": "_site",
"rewrites": [
{
"source": "/api/subscribe",
"function": "newsletterSubscribe"
},
{
"source": "/api/contact",
"function": "contactForm"
},
{
"source": "**",
"destination": "/404.html"
}
]
}
}
This routes /api/* requests to Cloud Functions while serving everything else as static Jekyll output — a clean way to add dynamic behaviour to a static site without reaching for a full backend.
Firebase Hosting free tier limits
| Resource | Spark (Free) | Blaze (Pay-as-you-go) |
|---|---|---|
| Storage | 10 GB | $0.026/GB |
| Transfer/month | 10 GB | $0.15/GB |
| Custom domains | Multiple | Multiple |
| SSL certificates | Free | Free |
| Preview channels | Yes | Yes |
| Cloud Functions rewrites | No | Yes |
For a personal blog or small project, the free Spark plan is likely sufficient. For a high-traffic site, switch to Blaze (pay-as-you-go) — there is no monthly fee, you only pay for what you use above the free limits.
Troubleshooting
firebase: command not found
Run npm install -g firebase-tools and ensure your npm global bin directory is in your PATH.
Deploy fails with Error: HTTP Error: 400
Run firebase login --reauth to refresh your authentication token.
Clean URLs not working
Ensure "cleanUrls": true is in firebase.json and you have run firebase deploy after making the change.
CSS/JS returning 404
Verify that _site/assets/ was generated by Jekyll before deploying. Check _config.yml does not exclude your assets directory.
Custom domain shows Firebase default page
DNS propagation can take up to 48 hours. Use dig yourdomain.com A to check if the records have propagated. The Firebase console also shows domain verification status.
Firebase Hosting is a solid choice for Jekyll if you are already in the Google/Firebase ecosystem or want built-in preview channels and instant rollbacks. For pure static site hosting without Firebase integration, Cloudflare Pages or Netlify are simpler to set up. But if you need to pair Jekyll with Firebase services — Auth, Firestore, Functions — Firebase Hosting is the natural fit.
Firebase Hosting vs other Jekyll hosts: an honest comparison
Firebase Hosting competes in a crowded field of excellent static site hosting options. Understanding where it leads and where it trails helps you decide whether it is the right choice for your specific situation.
Firebase Hosting’s performance credentials are strong. Google operates the underlying CDN infrastructure — the same network that serves Google’s own services — with edge nodes in all major regions. Time to First Byte is consistently low, comparable to Cloudflare Pages and Netlify. SSL is automatic and provisioned quickly. Global content delivery is reliable.
Where Firebase distinguishes itself from Netlify and Cloudflare Pages is in its integration with other Firebase services. If your Jekyll site needs to interact with Firebase Authentication (for gated content or member areas), Firestore (for real-time data), Cloud Functions (for server-side logic triggered by form submissions or content updates), or Firebase Analytics, Firebase Hosting provides the tightest integration. Assets served from Firebase Hosting and Firebase backend services share the same Google project, simplifying CORS configuration and authentication token validation.
Where Firebase falls short compared to its competitors is developer experience for pure static site hosting. Netlify’s deploy preview links on pull requests, Cloudflare Pages’ unlimited bandwidth free tier, and GitHub Pages’ seamless GitHub integration are features that Firebase does not match. The Firebase CLI is capable but requires more commands to achieve the same deployment workflow that Netlify or Cloudflare Pages automate through Git webhooks.
Setting up Firebase Hosting with GitHub Actions
Automating Jekyll deployments to Firebase Hosting through GitHub Actions removes the manual firebase deploy step and creates a continuous deployment pipeline where every push to main triggers a production deployment.
The GitHub Actions workflow installs Node.js, installs the Firebase CLI, installs Ruby and bundler, runs the Jekyll build, and then runs firebase deploy. Firebase authentication uses a service account key stored as a GitHub Actions secret — generate a key from the Firebase project settings, add it as a FIREBASE_SERVICE_ACCOUNT secret in your GitHub repository, and the workflow authenticates automatically.
For preview channels — Firebase Hosting’s equivalent of Netlify’s deploy previews — the official Firebase GitHub Actions integration creates a temporary preview URL for each pull request, posting the URL as a comment. This is configured by adding the FirebaseExtended/action-hosting-deploy action to your workflow, which handles channel creation, deployment, and cleanup automatically.
Optimising Firebase Hosting configuration
Firebase Hosting’s firebase.json configuration file controls headers, redirects, rewrites, and caching behaviour. Several optimisations are worth configuring from the start.
Cache headers for static assets should be aggressive. Add a headers block to firebase.json that sets Cache-Control: public, max-age=31536000, immutable for CSS, JavaScript, and image files. Jekyll does not automatically version these files, so you need a cache-busting strategy — appending a version query string to asset URLs in your layout files, and bumping the version when assets change.
Redirects for moved content are handled in the redirects array with source, destination, and status (301 for permanent, 302 for temporary). This is equivalent to Netlify’s _redirects file but configured in JSON syntax. If you are migrating from a different URL structure, comprehensive redirect configuration preserves inbound links and prevents 404 errors from accumulating in Search Console.
Security headers improve your site’s posture against common web vulnerabilities. Add a Content-Security-Policy header that allows scripts and styles from your own domain and approved CDN sources, a X-Frame-Options: DENY header to prevent clickjacking, and a Referrer-Policy: no-referrer-when-downgrade header for appropriate referrer disclosure. These headers are invisible to visitors but meaningfully reduce attack surface and may improve search ranking signals related to site security.
The case for Firebase Hosting in Google ecosystem projects
The clearest case for Firebase Hosting as your Jekyll host is when your site is part of a broader Google ecosystem architecture. Teams that use Google Cloud Platform for backend infrastructure, Google Analytics for analytics, Firebase Authentication for user management, and Google Workspace for team collaboration have a natural affinity for Firebase Hosting — everything is under one Google project umbrella, billing is consolidated, and authentication tokens work seamlessly across services.
For a developer blog with no backend requirements, Firebase Hosting is functional but not differentiated. For a documentation site that provides personalised code samples based on Firebase Authentication user data, or a landing page that triggers Firebase Cloud Functions on form submission, Firebase Hosting’s tight integration creates genuine architectural advantages.
If you are starting fresh with no existing Google Cloud commitments, evaluate Cloudflare Pages or Netlify before Firebase Hosting for pure static site use cases — they offer simpler setup, better developer experience features, and comparable or better performance at equivalent price points. Choose Firebase Hosting when the Google ecosystem integration is a genuine requirement, not as a default choice.