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.
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).
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.
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.
- In the YAML code above, look for
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.
