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: "$"
firebaseServiceAccount: "$"
channelId: live
projectId: jekyllhub
- name: Deploy PR preview
if: github.event_name == 'pull_request'
uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: "$"
firebaseServiceAccount: "$"
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.