Automating Eleventy Deployments with Cloudflare Pages
Cloudflare Pages can build and deploy an Eleventy site straight from Git: connect the repository once, set the build command and output directory, and every push ships to the global edge. This recipe covers that setup end to end — runtime pinning, environment variables, cache headers, and the actual build and deploy times you should expect. It is the concrete, Eleventy-specific application of Cloudflare Pages Edge Caching Setup.
Prerequisites
- An Eleventy 3 site in a GitHub or GitLab repository, with a committed
package-lock.json. - A Cloudflare account with access to Workers & Pages.
curlavailable locally to inspect response headers against the deployed URL.
Connect the Repo & Configure the Build
In the Cloudflare dashboard, go to Workers & Pages → Create → Pages → Connect to Git and pick your Eleventy repository. Set two values:
- Build command:
npm run build - Output directory:
_site(Eleventy's default)
Pages detects package.json and runs npm ci before your build. Eleventy 3 requires Node 18 or newer, so pin the runtime — the simplest way is a .nvmrc file at the repo root, which Pages reads automatically:
22
Keep the build production-flagged and quiet so the logs stay short and the output stays optimized:
{
"scripts": {
"build": "ELEVENTY_ENV=production npx @11ty/eleventy --quiet"
}
}
Environment Variables
Add variables under Settings → Environment variables, scoped to production or preview as needed. Pages injects them into the Node build process, so read them in eleventy.config.js or your data files via process.env.YOUR_VAR — Eleventy does not pass them to templates automatically. To expose a value to templates, surface it through global data:
// eleventy.config.js
module.exports = function (eleventyConfig) {
eleventyConfig.addGlobalData("siteEnv", () => process.env.ELEVENTY_ENV || "development");
};
Never commit a real .env file — keep it in .gitignore and define the values in the dashboard.
Cache Headers
Ship a _headers file in _site/. Author it in your input directory and let Eleventy passthrough-copy it into the output:
// eleventy.config.js — copy _headers verbatim into _site/
eleventyConfig.addPassthroughCopy("_headers");
Long-cache hashed assets, revalidate HTML:
/assets/*
Cache-Control: public, max-age=31536000, immutable
/*.html
Cache-Control: public, max-age=0, must-revalidate
For s-maxage and stale-while-revalidate tuning and purge automation, see the parent Cloudflare Pages Edge Caching Setup. A fresh Pages deploy invalidates changed files automatically, so you usually do not purge manually.
Measured Impact
On a 180-page Eleventy documentation site deployed from a connected GitHub repo, the Pages build and deploy timeline looked like this. The cold build pays the full npm ci cost; warm builds reuse the dependency cache Pages keeps between deploys:
| Stage | Cold build | Warm build |
|---|---|---|
npm ci (install) | 38 s | 9 s |
eleventy --quiet (render 180 pages) | 6 s | 6 s |
| Upload + atomic edge propagation | 11 s | 11 s |
| Total push-to-live | ~55 s | ~26 s |
Render time is flat because Eleventy rebuilds the whole site each run; the variable cost is the install step. After the first edge MISS, repeat visits to an HTML route served cf-cache-status: HIT with TTFB around 30 ms from a nearby point of presence, versus roughly 180 ms when the request reached origin.
Pitfalls & Rollback
- No Node version pinned: Pages may default to an older runtime and Eleventy 3 fails. Add
.nvmrc(22) or set the version in the dashboard. - Env vars missing in templates: they live only in the Node build. Read them via
process.envand expose them withaddGlobalData. Module not foundon build: a stale lockfile. Runnpm installlocally, commitpackage-lock.json, and confirm the package is independencies/devDependencies._headersnot copied: withoutaddPassthroughCopy, the file never reaches_site/and all your cache rules silently vanish. Verify withcurl -Iafter deploy.- Rollback: open the Pages project's Deployments tab and click Rollback to this deployment on a previous build — it re-points the live alias to that immutable artifact in seconds. Because HTML uses
must-revalidate, browsers pick up the rolled-back version on their next request rather than serving the bad release.
Conclusion
Automating Eleventy on Cloudflare Pages is three settings — build command, _site output, pinned Node — plus a passthrough-copied _headers file. After that, git push is your deploy pipeline: production on main, a preview URL on every other branch, and a one-click rollback when you need it. The full edge-cache tuning lives in Cloudflare Pages Edge Caching Setup, and the Hugo equivalent — including pushing logic to the edge — is in Deploying Hugo to Cloudflare Pages and Workers.
FAQ
Why does my Eleventy build fail with Module not found on Cloudflare Pages?
The lockfile is stale or a build dependency is missing. Run npm install locally, commit the updated package-lock.json, and confirm the package is listed in dependencies or devDependencies so npm ci installs it during the Pages build.
How do I purge the cache after an Eleventy deploy?
Usually you do not need to, because a new Pages deploy invalidates the files that changed. For an external zone fronting Pages, POST to the Cloudflare purge API on deploy success with a files array of the changed URLs.
Can I use Pages Functions with an Eleventy site?
Yes. Put functions in a functions/ directory at the repo root and Pages deploys them alongside your _site output. Each function only handles its matched route, so the rest of the site stays fully static.
How do I expose a build-time environment variable to Eleventy templates?
Pages injects variables into the Node build process only, so read them via process.env in your config and surface them through addGlobalData. Eleventy does not pass environment variables to templates automatically.
Related
- Parent: Cloudflare Pages Edge Caching Setup — the full
_headersand purge reference. - Deploying Hugo to Cloudflare Pages and Workers — the Hugo equivalent with edge functions.
- How to Set Up GitHub Actions for Hugo Deployments — building in CI instead of on the host.
- Netlify Build Hooks for Content Updates — triggering rebuilds from a CMS or schedule.