Jan 13, 2026 3 min read

Deploy Hugo + Tailwind v4 to Cloudflare: Super Fast GitHub Workflow

Deploy Hugo + Tailwind v4 to Cloudflare: Super Fast GitHub Workflow

So you want your Hugo site to fly, right? Like, blink-and-it’s-live kind of speed. I got you. We’re gonna set up a GitHub Actions workflow that takes your Hugo code (rocking Tailwind v4), builds it with the speed of light using pnpm, and yeets it onto Cloudflare Pages.

Here’s the breakdown on how to set this up for maximum speed and optimization. No fluff, just the good stuff. 🚀


Why this setup rocks

  • pnpm: It’s way faster than npm or yarn. It eats less disk space and installs dependencies like a hungry beast.

  • Cloudflare Pages: The CDN is insane. Your site loads instantly anywhere in the world.

  • Caching: We’re gonna cache your processed images so Hugo doesn’t have to rebuild them every single time. This is the speed hack.

  • Concurrency: If you push code twice rapidly, it cancels the first build so you don’t waste time.


The Secret Sauce (Your Workflow File)

Create a file in your repo at .github/workflows/deploy.yml and paste this bad boy in. This is the optimized code you asked for, tuned for Node 24 and pnpm.

YAML

name: Deploy Hugo + Tailwind v4

on:
  push:
    branches:
      - main

# Stops old builds if you push new code immediately. Saves time!
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          submodules: true
          fetch-depth: 0 # Needed for Hugo's .GitInfo

      - name: Setup pnpm
        uses: pnpm/action-setup@v4
        with:
          version: 9

      - name: Setup Node.js 24
        uses: actions/setup-node@v4
        with:
          node-version: 24
          cache: 'pnpm'

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v3
        with:
          hugo-version: 'latest'
          extended: true

      # THIS IS THE GAME-CHANGER for your site
      # Caches resized images so Hugo doesn't rebuild them every time
      - name: Cache Hugo resources (images)
        uses: actions/cache@v4
        with:
          path: resources
          key: ${{ runner.os }}-hugo-resources-${{ hashFiles('content/**', 'assets/**') }}
          restore-keys: |
            ${{ runner.os }}-hugo-resources-

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Build Hugo site
        run: hugo --gc --minify
        env:
          HUGO_ENVIRONMENT: production
          HUGO_ENV: production

      - name: Deploy to Cloudflare Pages
        uses: cloudflare/pages-action@v1
        with:
          apiToken: ${{ secrets.CF_API_TOKEN }}
          accountId: ${{ secrets.CF_ACCOUNT_ID }}
          projectName: olimiah # Change this to your actual project name!
          directory: './public'

How to set it up (The Boring Stuff)

You need to give GitHub the keys to your Cloudflare kingdom.

  1. Get your Cloudflare Info:

    • Account ID: Go to your Cloudflare Dashboard URL. The ID is the gibberish text after dash.cloudflare.com/.

    • API Token: Go to My Profile > API Tokens > Create Token. Use the “Edit Cloudflare Workers” template (it works for Pages too).

  2. Add Secrets to GitHub:

    • Go to your GitHub Repo.

    • Click Settings > Secrets and variables > Actions.

    • Add a New Repository Secret: CF_ACCOUNT_ID.

    • Add another one: CF_API_TOKEN.

  3. Check the Project Name:

    • In the YAML code above, look for projectName: olimiah. Make sure that matches exactly what you named your project in Cloudflare Pages.

Why we did what we did

  • fetch-depth: 0: Hugo loves Git info (like “Last Modified” dates). If you don’t do this, all your dates will be wrong.

  • pnpm install --frozen-lockfile: This ensures the CI server installs exactly what you have on your machine. No surprises.

  • The Cache Step: Seriously, if you have a lot of images that Hugo processes (resizing, cropping), this step saves minutes off your build time. It reuses the work from the last build.