How Antora assembles a site

This explanation covers the model underneath the commands you ran in the tutorial: what Antora actually does with your repositories, why the design splits content from assembly, and where the model's assumptions stop holding. Nothing here is required to operate a site; it's the page for the person who wants to know what the architecture is for.

The problem Antora is shaped by

General-purpose static site generators share an assumption: the site is a directory. Point the tool at a folder of files, get HTML out. That assumption quietly fails for product documentation, which is rarely one directory. It's the server docs in one repository and the client docs in another; it's version 1.4 that must stay published for the customers still running it; it's a snippet that twelve pages share and one team maintains.

You can fight a directory-shaped tool into doing this (submodules, copy scripts, a v1/ folder that drifts from reality). Antora's bet is different: the unit of content is a git reference, not a directory, and the site is a function over a set of them.

From playbook to site, in four stages

A build is a pipeline with a declarative recipe, the playbook, at the top:

  1. Aggregation. Antora clones or fetches every repository in content.sources into a local cache and reads the configured branches and tags directly from git's object database, without checking anything out. A working tree never exists; a branch is just a tree of blobs to read. This is why an uncommitted file is invisible to a normal build, and it's what makes "read main, v2.0, and v1.0 simultaneously" cheap.
  2. Classification. Files from each branch are sorted into a content catalog under coordinates, not paths: component and version (from that branch's antora.yml), module (from the directory under modules/), and family (page, partial, example, image, attachment, from the directory the file sits in). The rigid standard layout isn't bureaucracy; it's the parser.
  3. Conversion. Pages are converted from AsciiDoc, and every xref: and include:: is resolved as a lookup in the catalog, not on disk. A reference either resolves to a real resource, possibly in another component or version, or it's logged (and, with runtime.log.failure_level: error, fails the build). Link integrity is a property of the model, not a crawler bolted on afterward.
  4. Generation. The resolved pages are poured into the UI bundle's templates, navigation trees are built from the nav.adoc files, and the version selector falls out of the catalog's coordinates. The output is inert HTML; nothing of the pipeline survives into production.

Why versions are branches

The catalog's version coordinate comes from antora.yml as it exists on each branch, and that choice carries most of the workflow's value:

  • Freezing docs is free. A release branch exists the moment you cut it; its docs are frozen with it. No copying, no "snapshot the wiki" ritual.
  • Backports are cherry-picks. The operation teams already trust for code applies to docs unchanged, review included.
  • History stays honest. The 1.0 docs are whatever the v1.0 branch says, with every change attributed and revertible. A folder-per-version scheme preserves none of that once files are copied.

The subtler consequence: because version identity lives in the content repository rather than the playbook, the product team owns what "2.0" means, and the docs platform merely decides which versions to publish. That boundary — content repositories own truth, the playbook owns assembly — is the whole political design of Antora, and it's why a docs platform team can serve many product teams without being a bottleneck for any of them.

A relative file path encodes an accident: where two files happen to sit right now, in one version. A resource ID (1.0@widget:admin:backup.adoc) encodes an intent: this page, in that component, at a version I either pin or inherit from the reader. Intent survives reorganization; accidents don't.

IDs are also what make cross-version and cross-component references sane. An unqualified xref follows the reader's current version, so the 1.0 docs link within 1.0 and the 2.0 docs link within 2.0 — from the same source line, cherry-picked between branches without edits.

Where the model leaks

Honest limits, so you can decide with your eyes open:

  • The layout is non-negotiable. Content must live under modules/<name>/<family>/. Migrating an existing docs tree means moving files into that shape first; there is no "just point it at my folder."
  • Builds are whole-site. Antora rebuilds everything the playbook names on every run. Sites in the thousands of pages build in minutes, not seconds: fine for CI cadence, occasionally irritating for local preview during heavy writing sessions.
  • The UI bundle is a second artifact. Decoupling the frontend from content builds is the right call, but customizing the default UI means owning a fork of a Gulp-era frontend project. Budget for it once, then leave it alone.
  • Attributes are a global namespace. AsciiDoc attributes make single-sourcing possible and, past a point, make pages hard to read without building them. Keep a short, documented attribute vocabulary; resist the urge to parameterize prose that was fine as prose.
  • It's docs-shaped, deliberately. Antora generates documentation sites. Marketing pages, blogs, and app-like frontends belong in other tools, and the teams that accept that early are happier than the ones that fight it.

What to take away

The pipeline view explains the operational rules of thumb elsewhere in this documentation: content must be committed because aggregation reads git, not your working tree; antora.yml is read per branch because that's where version identity lives; xrefs are cheap to validate because resolution is a catalog lookup; and the playbook repository stays tiny because assembly is the only thing it owns.

If that model matches your documentation problem (several sources, several versions, one site), very little else in this space is built for it. If it doesn't, a simpler directory-shaped tool will serve you better, and the overview says so without hard feelings.