How to rebuild a Cloudflare site on a schedule

By

Learn how to rebuild a Cloudflare Pages site on a schedule using a deploy hook, triggered either by a GitHub Action cron or a Cloudflare Worker cron.

~~~

A static site on Cloudflare Pages rebuilds when you push to Git. Most of the time that’s exactly what you want.

Sometimes you need it to rebuild on a schedule without a push.

I hit this with scheduled blog posts. I write a post, give it a future date, and the site hides it until that day. But “until that day” only works if the site rebuilds on that day. Nobody’s pushing at 7am to make a post go live.

The same need comes up for a site that shows data which goes stale: prices, a changelog, anything pulled in at build time.

I considered two ways to trigger the rebuild.

The key piece: a deploy hook

Cloudflare Pages has a feature called a deploy hook. It’s a secret URL. POST to it, and Cloudflare runs a fresh build and deploy, exactly as if you’d pushed.

You create one in the dashboard: open your Pages project, then Settings → Builds & deployments → Deploy hooks. Give it a name, pick the branch to build (for me, master), and you get a URL.

Test it from your terminal:

curl -X POST "https://api.cloudflare.com/client/v4/pages/webhooks/deploy_hooks/your-hook-id"

Run that, check your dashboard, and you’ll see a new build start.

Now you need something to call the URL once a day.

Option 1: a GitHub Action

If your code already lives on GitHub, the simplest trigger is a scheduled workflow that curls the hook.

Create .github/workflows/scheduled-rebuild.yml:

name: Daily rebuild

on:
  schedule:
    - cron: "15 5 * * *"
  workflow_dispatch: {}

jobs:
  rebuild:
    runs-on: ubuntu-latest
    steps:
      - run: curl -fsS -X POST "${{ secrets.CF_PAGES_DEPLOY_HOOK }}"

If you’re switching between YAML and JSON while editing workflow files, I built a free YAML ↔ JSON converter that runs in your browser.

Put the hook URL in a GitHub secret called CF_PAGES_DEPLOY_HOOK (repo Settings → Secrets and variables → Actions), so it’s not in your code.

That workflow_dispatch line lets you also trigger it by hand from the GitHub UI, which is handy for testing.

Advantages

Limits

Option 2: a Cloudflare Worker cron

The other way keeps everything on Cloudflare. You make a tiny Worker that runs on a schedule and fetches the hook.

The Worker only needs to call the hook:

export default {
  async scheduled(event, env, ctx) {
    await fetch(env.DEPLOY_HOOK, { method: 'POST' })
  },
}

Its wrangler.jsonc sets the schedule:

{
  "name": "daily-rebuild",
  "main": "src/index.ts",
  "compatibility_date": "2026-06-20",
  "triggers": {
    "crons": ["15 5 * * *"]
  }
}

Store the hook URL as a secret and deploy:

npx wrangler secret put DEPLOY_HOOK
npx wrangler deploy

Advantages

Limits

Which one I’d pick

Both options hit the same deploy hook. The Worker can’t build your site itself, since Cloudflare’s build system runs the build. It only sends the same POST request as the Action.

The difference is the wrapper around that POST. A GitHub Action is one file in a repo you already have, while the Worker is a separate deployable.

So my rule of thumb:

Both work. Pick based on where you want the moving part to live.

One gotcha: time zones

Whichever you choose, the cron runs in UTC. My posts go live at 07:00 my time, which is 05:00 UTC, so I schedule the rebuild at 15 5 * * *, a little after, to be safe.

If you set a schedule and the rebuild seems to happen at the wrong hour, this is almost always why.

Documentation

The deploy hook details are in the Pages docs, and the Worker schedule side is in the Cron Triggers docs.

Want me to talk about your product? You can sponsor this site.

~~~

Related posts about cloudflare: