Home Blog How to Deploy a Jekyll Site to Firebase Hosting (2026 Guide)
Tutorial

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.

How to Deploy a Jekyll Site to Firebase Hosting (2026 Guide)

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 Gemfile and committed Gemfile.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

  1. Go to console.firebase.google.com
  2. Click Add project
  3. Enter a project name (e.g. jekyllhub)
  4. Disable Google Analytics if you do not need it (you can add it later)
  5. 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.html when someone visits /about or /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 CDN
  • rewrites — the catch-all to 404.html handles 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

  1. In the Firebase console, go to HostingAdd custom domain
  2. Enter your domain (e.g. jekyllhub.com)
  3. Firebase shows DNS records to add:
    • Two A records for the root domain pointing to Firebase’s IP addresses
    • A CNAME for www pointing to your-project.web.app
  4. Add these records at your domain registrar
  5. 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:

  1. Firebase console → HostingRelease history
  2. Find the release you want to restore
  3. 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

  1. Firebase console → Project settingsService accounts
  2. Click Generate new private key → Download the JSON file
  3. 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.

Share LinkedIn