Cloud
Cloudflare Pages, Node 22, and Why Boring Deployments Win
A practical case for keeping static technical publishing simple on Cloudflare Pages, with explicit runtime pinning and Git-driven releases.
For a technical content site, the fastest way to lose momentum is to choose a deployment path that is more ambitious than the project itself.
If the goal is a lightweight publication platform with Markdown or MDX content, predictable builds, and very little operational overhead, a static site on Cloudflare Pages is still a strong option. The nuance matters, though. Astro’s current Cloudflare guidance now focuses heavily on Workers for full-stack and on-demand rendering scenarios, while Cloudflare Pages documentation still supports standard Git-connected static deployments and explicitly lists Astro with npm run build as the build command and dist as the output directory. In other words, Pages remains a good fit when the site is static-first and the architecture is intentionally boring.
Keep the architecture boring on purpose
The most reliable technical sites are usually the least magical ones:
- source files in Git
- content in MDX
- static HTML output
- deployment triggered by a push to
main - no database, no runtime state, no fragile build chain
That approach makes failures easier to reason about. When a build breaks, the problem is usually one of four things: missing dependencies, incorrect build settings, wrong repository structure, or an asset that was never committed.
For a static-first Astro site, an explicit configuration like this keeps the intent obvious:
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
export default defineConfig({
integrations: [mdx()],
output: 'static'
}); Git-driven deployment is the feature, not a detail
For a content site, Git integration is one of the biggest operational advantages of Pages.
A push to the production branch should be enough to trigger a new deployment. That keeps the release model boring and auditable:
git add .
git commit -m "Publish new article"
git push origin main That flow is especially valuable once the site starts to carry actual content. It keeps design changes, article additions, and infrastructure tweaks in the same traceable history.
Pin your Node version deliberately
One detail that is easy to miss on Cloudflare Pages is runtime version handling.
Cloudflare’s current v3 build image ships with Node.js 22 by default, and it allows version overrides with NODE_VERSION, .nvmrc, or .node-version. At the same time, the v3 build system does not detect Node.js versions from package.json engines. If your build depends on a specific Node version, pin it explicitly instead of assuming engines will be honored in the Pages environment.
A small file at the project root is often enough:
22.12.0 That one decision removes a whole class of “works locally, fails in CI” problems.
The failure modes worth checking first
When a static Astro site fails on Pages, start with the boring checks:
- Is the app rooted where Pages thinks it is?
- Does the build actually produce
dist/? - Was the change really pushed?
- Is the asset referenced by the page actually committed into
public/?
Run the same command locally that Pages will run:
npm run build If local output is not landing in dist, fix that first.
Use case: small technical publication platforms
For a personal or team-owned technical publication, the practical use case is straightforward. You want:
- a fast static frontend
- low deployment friction
- minimal runtime cost
- infrastructure you do not need to babysit
Cloudflare Pages plus Astro still fits that shape well. The mistake is usually not choosing Pages. The mistake is adding complexity before the site actually needs it.