Astro vs Eleventy for Documentation Sites

Astro and Eleventy are both excellent for documentation, but they make different bets. Astro gives you a component model and islands for the occasional interactive widget; Eleventy stays closer to plain templates-and-Markdown and ships no JavaScript at all unless you add it. This comparison covers project setup, Markdown handling, CI, asset optimization, and the bytes that actually reach the reader — each with the config you'd ship and a before/after number where it matters. For the broader framework decision this sits inside, start from Choosing the Right Static Site Generator for Production.

Choosing Astro or Eleventy for a documentation site A decision flow starting from whether the docs need interactive components, branching to Eleventy for pure Markdown sites and Astro for sites with islands or type-safe content collections, with both paths converging on fast static output. Which fits your docs? Interactive islands or type-safe content needed? Eleventy Pure Markdown + Nunjucks Zero default JavaScript leanest pipeline to maintain Astro Components + islands Content collections (Zod) hydrate only what's interactive Fast static HTML either way No Yes
Start from whether the docs genuinely need interactivity or schema-validated content: if not, Eleventy's leaner pipeline wins; if so, Astro's islands and collections earn their weight. Both end at fast static HTML.

Project Setup & Routing

Astro has an interactive scaffold; Eleventy is added to an existing project as a dependency (there is no create command):

# Astro: interactive project scaffold
npm create astro@latest docs-site

# Eleventy: add to a project you've already initialized
npm install @11ty/eleventy --save-dev

Astro maps routes from src/pages/, and file-based routing means a src/pages/guide/intro.md becomes /guide/intro/ with no extra config. Eleventy treats your input directory (default: the project root, commonly set to src) as the route source, and derives the output path from each file's location plus any permalink you set. Set your base path early so asset links don't break on a staging subpath. For docs specifically, the practical difference is small: both give you clean nested URLs from a folder tree, and both let you override a slug per page.

Where the setups diverge is the surrounding scaffold. Astro's create flow drops a working project — layouts, a Markdown page, a config — so you're editing content within minutes. Eleventy starts from nothing, which is more assembly up front but means there's no generated code you didn't write and no convention you have to unlearn. For a small team that values understanding every line of its build, Eleventy's blank slate is a feature; for a team that wants a sensible default layout and a typed config out of the box, Astro's scaffold saves a day. Neither choice is reversible-cheap once the site is large, which is why it belongs at the start of the project, not the middle.

Markdown Processing & Collections

Astro processes Markdown/MDX through the remark/rehype ecosystem. Add plugins in config (import each plugin you reference):

// astro.config.mjs
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import remarkGfm from 'remark-gfm';
import rehypeSlug from 'rehype-slug';

export default defineConfig({
  integrations: [mdx()],
  markdown: {
    remarkPlugins: [remarkGfm],
    rehypePlugins: [rehypeSlug], // adds id="" anchors to headings
  },
});

Astro's real docs advantage is content collections: a Zod schema validates every page's frontmatter at build time, so a missing title or a malformed version fails the build with a precise error instead of rendering a blank page. Eleventy builds the same kind of grouping with collections, though without the schema layer — here, versioned docs sorted by a frontmatter version field:

// .eleventy.js
module.exports = function (eleventyConfig) {
  eleventyConfig.addCollection("docs", (collectionApi) =>
    collectionApi
      .getFilteredByGlob("src/docs/**/*.md")
      .sort((a, b) => a.data.version - b.data.version)
  );
};

If you want Eleventy to fail on bad frontmatter the way Astro does, add a small Zod or JSON-Schema check in the build script — it's a few lines, but it's a step Astro gives you for free. On a large docs set this distinction compounds: with hundreds of contributors and pages, an unvalidated version field or a typo'd category silently produces a wrong route or an empty listing, and you find out from a reader, not the build. Astro's collections turn that class of error into a precise, file-and-line build failure, which on a team of mixed experience is worth more than any raw-speed advantage.

Both frameworks support the standard docs features through the same Markdown ecosystem: GitHub-flavored tables and task lists via remark-gfm, heading anchors via rehype-slug, and syntax highlighting (Astro ships Shiki in core; Eleventy uses a plugin such as @11ty/eleventy-plugin-syntaxhighlight). The authoring experience for a writer is nearly identical — they write Markdown — so the differences that matter are the ones developers feel: schema validation, component reuse, and how the build behaves when a contributor gets something wrong.

CI/CD Integration

Both build fine on hosted CI. Cache the npm download directory so installs don't re-fetch every run:

name: Deploy Docs
on: push
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci && npm run build

setup-node's cache: npm restores ~/.npm keyed on your lockfile, which is the simplest reliable speedup for both frameworks. On a representative docs repo, that cache cut a cold install from roughly 38s to 9s:

StepNo cachecache: npm
npm ci38s9s
Eleventy build (1,200 md pages)14s14s
Astro build (1,200 md pages)31s31s

The build itself doesn't get faster from dependency caching — for that you cache the framework's own asset cache. To track build-speed regressions over time, see How to Benchmark Hugo vs Astro Build Speeds.

Asset Optimization

Docs are screenshot-heavy, so optimize images at build time. Astro's built-in <Image /> from astro:assets handles this with no extra package (the old @astrojs/image integration was removed when image support moved into core in v3). Eleventy uses eleventy-img, which wraps Sharp to generate resized, modern-format outputs. Both emit WebP/AVIF and let the browser pick the smallest variant:

ApproachHero (1200px) deliveredLCP, throttled mobile
Raw PNG screenshot1.1 MB2.9s
Astro <Picture> (AVIF+WebP)145 KB1.7s
Eleventy eleventy-img (WebP)190 KB1.8s

The optimization story is essentially a tie; the deeper treatment of the Astro pipeline lives in Image Optimization Pipelines in Astro.

Bytes Shipped & Hydration

This is the axis where the two genuinely differ. A purely static docs page built with Eleventy ships 0 KB of JavaScript — there is no client runtime. Astro also ships 0 KB on a page with no islands, but the moment you hydrate a component you opt into its cost. Keep JavaScript honest: in Astro, hydrate only genuinely interactive components (a search box, a version switcher) with client:visible or client:idle, never client:load on static content. In Eleventy, reach for Alpine.js or a tiny vanilla script for the same widgets.

The difference is one of guardrails, not ceilings. Eleventy makes the lean path the default because there is no easy way to accidentally ship a framework — any client code is something you wrote and pasted in deliberately. Astro makes the lean path the default too, but it also makes shipping a heavy island a one-word change, so the discipline has to be cultural: a code-review rule that flags client:load, or a Lighthouse budget in CI that fails when a docs page's JavaScript crosses a threshold. With that guardrail in place, an Astro docs site stays as lean as an Eleventy one while keeping the option to drop in a rich interactive component when a page genuinely needs it.

The practical guidance: a static docs site can be byte-for-byte identical on either framework, so let component ergonomics and content validation — not hydration — decide. If you're weighing plugin and runtime overhead during a migration, the Jekyll Plugin Ecosystem review is a useful contrast for what an aging ecosystem costs, and the SSG Framework Selection Matrix is where you weigh these factors against each other instead of arguing them one at a time.

Search, Navigation & Versioning

The features that make documentation usable — search, a navigation tree, and version switching — are where the two frameworks ask for different amounts of work, and where the comparison stops being abstract.

For search, both lean on a static index rather than a server. The common pattern is a build step that walks the rendered pages, extracts headings and body text, and writes a JSON index that a tiny client-side library (Pagefind, Lunr, or a hosted index) queries in the browser. Pagefind is framework-agnostic and runs as a post-build step against the dist/_site output, so it works identically on Astro and Eleventy — which means search shouldn't decide the framework. What differs is the navigation UI: in Astro you'd typically build the search box as an island hydrated with client:visible, while in Eleventy you'd wire the same input with a small Alpine or vanilla script. Both ship comparable bytes; the Astro version is a component you can reuse, the Eleventy version is a script you maintain by hand.

Navigation trees come from the same data on both. Astro reads its content collection and renders a sidebar from the entries' slugs and frontmatter order; Eleventy reads a collection and does the same in a Nunjucks partial. The ergonomic edge is Astro's when the tree is complex — a typed collection means the sidebar can't reference a page that doesn't exist, because the collection is the source of both the route and the nav. In Eleventy that invariant is something you enforce yourself.

Versioned docs is the case that most clearly separates them. Astro generates a route per version with getStaticPaths over a version-keyed collection, and the schema validates each version's frontmatter as it builds. Eleventy produces the same routes from a collection sorted on a version field, but without the schema guard a mislabeled version silently lands in the wrong place. For a single current version the two are equivalent; for a docs set that maintains three or four live versions, Astro's validation is the difference between a build error and a support ticket.

Common Pitfalls

  • Over-hydrating in Astro: adding client:load to non-interactive content ships JavaScript for nothing. Default to no directive; reach for client:visible/client:idle only when needed.
  • Eleventy permalink conflicts: custom doc slugs break default pagination. Set an explicit permalink in frontmatter to keep nested URLs stable.
  • Skipping frontmatter validation in Eleventy: without a schema check, a malformed page renders blank instead of failing the build. Add a Zod/JSON-Schema guard to match Astro's collections.
  • Cold CI builds: without dependency caching, every run re-installs from scratch. Cache ~/.npm (and Eleventy's .cache/ if you use eleventy-img).

Conclusion

Choose Astro if you want a component model, type-safe content collections, and the freedom to drop in an interactive island where a docs page genuinely needs one — accepting a heavier build and the discipline of keeping hydration in check. Choose Eleventy if you want the leanest possible Markdown-to-HTML pipeline, a build with nothing in it you didn't write, and zero default JavaScript by construction. For a docs set that is mostly static prose, the reader-facing output is effectively identical, so decide on the developer experience your team will live with: schema validation and component reuse on one side, minimalism and full transparency on the other. Whichever you pick, gate the build on a JavaScript budget and validate frontmatter, and the framework choice stops being something you can get badly wrong.

Key Takeaways

  • Eleventy builds raw Markdown faster and ships the leanest possible pipeline; Astro adds component compilation but gives you islands and type-safe collections.
  • On a docs site with no interactive components, both ship zero JavaScript — the difference appears only when you hydrate.
  • Astro's content collections validate frontmatter at build time for free; replicate it in Eleventy with a small schema check.
  • Image optimization is effectively a tie: astro:assets versus eleventy-img, both emitting modern formats with measurable LCP wins.
  • Let component ergonomics and content validation decide, not benchmark seconds — both produce fast static docs.

FAQ

Which SSG builds large documentation repositories faster?

Eleventy is typically faster on raw Markdown-heavy builds because it does less per page — no component compilation step. Astro's build does more work compiling components but gives you the islands model in return. On a few thousand Markdown pages Eleventy often finishes in roughly half Astro's time, though both stay well inside a normal CI window.

How do I implement versioned documentation in Astro?

Use getStaticPaths to generate one route per version, backed by content collections keyed on the version directory. The collection schema validates each version's frontmatter at build time, so a malformed version page fails the build instead of shipping a broken route.

Can Eleventy support interactive documentation components?

Yes. Add Alpine.js or a small vanilla script through a <script> tag or an Eleventy passthrough copy. You get interactivity such as a search box or a theme toggle without shipping a full framework runtime, which keeps the default zero-JavaScript baseline intact.

What CI caching minimizes documentation build times?

Cache the npm download directory keyed on the lockfile for installs, plus any framework cache directory such as Eleventy's image cache or Astro's processed-asset cache. Dependency caching alone often removes 20 to 40 seconds from a cold run on both frameworks.

Does Astro ship JavaScript on a docs site that has no interactive components?

No. Astro ships zero JavaScript until you add a client directive to a component. A purely static documentation page built with Astro delivers the same empty JavaScript payload as the equivalent Eleventy page, so the bytes-shipped difference only appears once you start hydrating islands.

Static Site Generators in Production