CMS for Eleventy (11ty): Headless Content for Your Static Site
Give editors a real UI without giving up static HTML
Eleventy (11ty) is the static site generator developers reach for when they want speed without a JavaScript framework tax. It takes your data and templates, spits out plain HTML, and gets out of the way. The catch: 11ty needs a source for that data. For a personal site, markdown files in a folder are fine. For anything a non-developer touches — a company blog, a client site, a docs section — you need a CMS behind it.
This post covers how to pair a headless CMS with Eleventy, what to fetch at build time, and why a self-hosted content layer fits the 11ty philosophy of owning your output.
How a CMS plugs into Eleventy
Eleventy builds at deploy time. It reads data, applies templates, and writes static HTML. A headless CMS becomes one of those data sources: 11ty calls the CMS API during the build, gets JSON back, and turns each record into a page.
The connection point is Eleventy's JavaScript data files. You drop a file in _data/, fetch from your CMS inside it, and every template can read the result. No plugin, no adapter — just a fetch call.
// _data/posts.js
export default async function () {
const res = await fetch(
'https://cms.yoursite.com/api/v1/posts?per_page=100'
);
const json = await res.json();
return json.data;
}
Now posts is available everywhere in your templates. Loop it into a blog index, or use pagination to generate one page per post.
Why self-hosted headless fits 11ty
Eleventy people tend to care about two things: build speed and owning the output. A SaaS CMS with usage-based API pricing works against both — every build hits the API, and a full rebuild of a large site can mean hundreds of requests you're metered on.
A self-hosted CMS removes the meter. UnfoldCMS is one option: it's a self-hosted CMS on Laravel with a REST API at /api/v1/*. You run it on your own box, so build-time fetches cost nothing extra, and the content lives in your database, not someone else's cloud.
What matters for the 11ty case:
- Plain REST — no GraphQL layer, no client library.
fetchin a data file is the whole integration. - No SDK to install — nothing to add to
package.json, nothing to break on the next major version. - Pay once — a static site that rebuilds often doesn't rack up API charges.
Generating a page per post
Eleventy's pagination turns a data array into individual pages. Point it at your CMS data:
---
pagination:
data: posts
size: 1
alias: post
permalink: "/blog/{{ post.slug }}/"
---
<article>
<h1>{{ post.title }}</h1>
{{ post.body | safe }}
</article>
Each post from the CMS becomes its own URL. The body field comes back as rendered HTML, so you output it with the safe filter. Titles, slugs, and dates map straight from the API response.
Keeping the static site fresh
The hard part of any static setup: an editor publishes, but the live site is a build from an hour ago. Eleventy doesn't know content changed. You have to rebuild.
Wire this up with webhooks. UnfoldCMS fires an outgoing, HMAC-signed webhook on content events — post published, updated, deleted. Point that webhook at your host's build hook:
Editor publishes in CMS
→ CMS sends signed POST to your deploy hook
→ Netlify / Cloudflare Pages rebuilds the 11ty site
→ Fresh HTML live in about a minute
The HMAC signature means your endpoint can verify the request is really from your CMS. Without this, static + headless is a manual chore. With it, publishing feels instant even though the site is fully static.
When markdown files are enough (and when they aren't)
Be honest about the baseline. If you're the only person editing, and you're comfortable in git, 11ty + local markdown is hard to beat: free, versioned, no server. A CMS adds value at a specific line:
| Situation | Markdown files | Headless CMS |
|---|---|---|
| Solo developer editing | ✅ Ideal | Overkill |
| Non-developer needs to edit | ❌ Painful | ✅ The point |
| Scheduled publishing | ❌ Manual | ✅ Built in |
| Media library for images | ❌ Manual | ✅ Built in |
| Multiple authors | ❌ Merge conflicts | ✅ Roles |
Cross the line where someone non-technical needs to publish, and the CMS earns its place.
Tradeoffs to know
- Preview takes wiring. The public API returns 404 for drafts, so previewing unpublished content means building a token-authed preview route yourself.
- No revision history. UnfoldCMS doesn't store past versions of a post — you can't roll back to yesterday's copy. Plan around it if you need audit trails.
- You run the server. Self-hosting means backups and updates are yours. A small VPS handles a content API easily, but it's still infrastructure you own.
FAQ
Does Eleventy need a plugin for a headless CMS?
No. Eleventy's JavaScript data files can fetch from any API. There's no adapter or plugin to install for UnfoldCMS — you write one small file in _data/.
Will build-time fetches slow down my 11ty build?
One paginated call for all posts is fast. For large sites, fetch everything in a single request (high per_page) rather than one call per post, and cache the response during local development.
How do I rebuild when content changes? Register an outgoing webhook in the CMS pointed at your host's build hook. On publish, the CMS triggers a rebuild automatically.
Does it support GraphQL?
No — REST only. For 11ty data files, REST plus fetch is simpler anyway.
Bottom line
Eleventy + a self-hosted headless CMS keeps the 11ty promise — static HTML you own — while giving non-developers a real editor. The integration is one data file and a fetch. Add a webhook so builds stay fresh, accept that preview and revisions need a little setup, and you've got a content workflow that scales past a folder of markdown.
See the API in the demo or read the headless CMS for Jamstack guide.
Related: CMS for Next.js · Headless CMS for Jamstack · Host a CMS on a $5 VPS
Free & Open Source
Own your CMS. No subscriptions.
Unfold CMS is free to download and self-host. Built on Laravel + React, full source code included.
Share this post: