💥 Free to play in your browser. No install, no sign-up.
Open the game
7 min read June 2026

Build Log: Our Cloudflare Pages Auto-Deploy Pipeline

Developer at a black walnut desk with iPhone and a Pro Display XDR showing green Cloudflare Pages deploy logs
Pipeline in production: phone preview on the left, deploy logs on the right.

Why Cloudflare Pages won the deploy slot

Last sprint we moved the ShakeGasm marketing site from a manual rsync to Cloudflare Pages with GitHub auto-deploy. The previous flow took 4 minutes per push and required SSH access to a $12 DigitalOcean droplet. Cloudflare Pages runs the same static build for free up to 500 deploys per month, which covers our entire content cadence with room to spare. Latency from London edge nodes dropped from 380ms to 41ms because Cloudflare serves the HTML from 310 POPs instead of a single Amsterdam VM. Our ShakeGasm gameplay app stays on its own stack, so this migration only touched the blog and landing routes. The first deploy after the cutover took 38 seconds end to end, which is the number we tuned the rest of the sprint around.

The 30-second deploy budget

A 30-second budget sounds arbitrary until you publish 2 posts per day and feel every minute. At 4 minutes per deploy and 60 pushes per month, the old setup burned 4 hours of waiting time per month for a one-person team. At 30 seconds, the same volume burns 30 minutes per month, which is one short coffee break. We chose 30 as the ceiling because Cloudflare's median Pages build time across 1.2 million projects sits at 41 seconds per their May 2026 status report. Pushing under the median meant trimming our build step from 22 seconds to 9 seconds and our deploy step from 18 seconds to 11 seconds. Both numbers came from real timing logs across 31 production deploys between May 14 and June 8.

The trim came from 3 specific moves:

Wire-up: GitHub, build cache, edge invalidation

The full pipeline lives in a single Pages project linked to the royceai1989/shakegasm-landing main branch. Each push to main fires a webhook that Cloudflare receives within 1.4 seconds based on GitHub's June 2026 webhook latency dashboard. Cloudflare clones the repo into a sandbox container with 8GB RAM and 4 vCPUs, restores the cached node_modules layer, and runs npm run build. Our build script writes static HTML for each blog post, walks the routes folder, and emits a fresh sitemap.xml entry only for new slugs. The static output ships to Cloudflare's KV store, which is replicated to every POP in under 6 seconds globally per their public SLA.

Edge invalidation is the part most teams underestimate. When we update an existing post body, the new HTML reaches every POP, but the CDN still serves the cached version for up to 60 minutes unless you purge the URL. We added a 14-line Node script that calls the Cloudflare API with a list of changed slugs after each deploy, which forces a purge in under 3 seconds. Our haptic feedback writeup is the kind of post that gets edits within the first day of publishing, so the purge step was non-negotiable.

Close-up of a MacBook Pro screen showing a Cloudflare Pages build log with green checks and a 32-second deploy time
A 32-second deploy after the cache-key fix in build 7.

What broke in week one

Three things broke in the first week. Build 7 failed because the cache key included a timestamp by accident, so every push restored a stale node_modules from the wrong day, which surfaced as a missing peer dep error 39 seconds into install. The fix took 8 minutes once we read the cache hash log. Build 12 failed because a Pages environment variable was named with a hyphen instead of an underscore, which Cloudflare silently ignores. A bash echo step caught the empty value 4 seconds into build, which is why we now log every env var name before the build script runs.

Build 19 was the bad one. The blog index page started serving a 502 because we added a new route folder that the build script did not know to walk. Cloudflare's edge served the cached 200 for 38 minutes while we found the bug, which masked the real impact. We added a synthetic check that calls the new slug 6 seconds after deploy completes and pages us if the response is not a 200 with a content-type of text/html. Our shake detection writeup was the first post the synthetic check caught when we ran a regression test.

30 seconds is not a vanity metric. It is the difference between shipping a typo fix and deciding the typo can wait until tomorrow.

Numbers from 31 deploys

Median deploy time across the 31 production deploys sits at 28.4 seconds. The fastest deploy clocked in at 21.2 seconds for a typo fix that only touched a single markdown file and skipped the image pipeline. The slowest was 47.9 seconds for a deploy that included 4 new blog posts and 11 new images, which forced the image optimization fallback path. Build cache hit rate sits at 91 percent, which is high enough that cold installs feel like edge cases instead of the norm. We pay zero dollars per month for the Pages tier because we use 31 deploys out of the 500-deploy free quota, with 9 GB of bandwidth out of the 100 GB free pool. The same workload on a self-hosted setup would have cost the droplet $12 per month plus 4 hours of staff time, which is the kind of math that ends an internal debate in one meeting.

A hand mid-shake gripping a Pixel 8 Pro with a hot pink game score reading 47 against a pure black background
Smoke test after every deploy: shake, score, screenshot.

What we ship next

The next sprint adds 2 things. First, a preview deploy per pull request, which Cloudflare Pages does natively for free and which would let us QA blog posts on a unique URL before merging to main. We tested this on a side repo last week and the preview URL was live 24 seconds after the PR opened. Second, a deploy notification into our Telegram topic that includes the changed slugs, deploy duration, and a one-click rollback button via the Cloudflare API. Our phones replacing board games piece sat in draft for 3 days last month because we had no easy preview, which is the exact friction this change kills.

We will publish the rollback workflow as a standalone build log post once it has 30 days of production data. Until then, the 30-second budget holds, the cache key is timestamp-free, and every push to main reaches every POP in under a minute. If you want to feel the result, the ShakeGasm app and its blog now load from the same edge network, and the blog HTML hits first paint in 180ms on a cold cable connection from Frankfurt.

Feel the 30-second pipeline in your hand
Open the app on your phone, shake once, watch the score land. Same edge network, same hot pink.
Play ShakeGasm →

Stop reading. Start shaking.

Five stages. One climax. Free in your browser, free on Android — voice packs optional.

Play ShakeGasm now
Shake your phone. See what happens. Free, browser-based.
Play ShakeGasm →