Your first Antora site
This tutorial teaches the docs-as-code workflow by building it. In about 45 minutes you'll create a documentation component inside a product repository, write a few pages in AsciiDoc, assemble them into a site with Antora, and make the kind of change (a reusable snippet, a cross-reference) that shows why this toolchain is worth the setup.
You don't need to know AsciiDoc or Antora. You do need to be comfortable running commands in a terminal and making git commits.
What you'll build
Two directories that mirror how real teams organize this:
widget/: a stand-in for your product repository, with adocs/directory holding the documentation component.docs-site/: the playbook repository that knows how to assemble one or more components into a published site.
Keeping them separate from the start matters: the product team owns the content, the docs platform owns the site, and neither blocks the other.
Prerequisites
- Node.js 18 or newer. Antora is a Node application. Check with
node --version. - git, with any name/email configured.
- A browser for admiring the result.
1. Create the documentation component
Antora doesn't crawl your repository looking for docs; it reads a component, a directory with a descriptor file and a fixed layout. Create the skeleton:
mkdir -p widget/docs/modules/ROOT/pages
cd widget
git init
The layout under docs/ is Antora's standard structure:
docs/
├── antora.yml <- component descriptor
└── modules/
└── ROOT/ <- the default module
├── nav.adoc <- navigation tree
├── pages/ <- one .adoc file per page
├── partials/ <- reusable snippets
└── examples/ <- code samples for inclusion
ROOT is the module whose pages sit at the component's root URL; extra
modules (say, admin/) become URL subpaths when you need them. Don't invent
a different layout; the fixed structure is what lets Antora resolve
references between files without configuration.
Now the descriptor. Create docs/antora.yml:
name: widget
title: Widget
version: '1.0'
nav:
- modules/ROOT/nav.adoc
Two things deserve attention. The name is the component's stable identity
in URLs and cross-references. Pick it once, keep it lowercase, and never
brand it. And version is quoted because YAML would otherwise read 1.0 as a
number; Antora wants a string.
2. Write the first pages
Create docs/modules/ROOT/pages/index.adoc:
= Widget Documentation
:description: What Widget is and where to start.
Widget is a small service that does one thing well. These docs cover
installing it, operating it, and understanding why it behaves the way
it does.
== Where to start
* If you're new, start with xref:install.adoc[Install Widget].
* If Widget is already running, see the operations pages in the
navigation.
And a second page, docs/modules/ROOT/pages/install.adoc:
= Install Widget
:description: Install Widget from a release tarball.
This page walks through a first-time installation.
== Download and unpack
[source,bash]
----
curl -LO https://example.com/widget/widget-1.0.tar.gz
tar -xzf widget-1.0.tar.gz
----
== Verify the installation
[source,bash]
----
widget --version
----
NOTE: If the command isn't found, make sure the unpacked directory is on
your `PATH`.
That's most of the AsciiDoc you need on day one: =/== for headings,
* for bullets, [source,bash] + ---- fences for code, NOTE: for
admonitions, and xref: for links between pages. The xref:install.adoc[]
form is the habit to build early: Antora resolves it at build time and
complains if the target doesn't exist, which is the difference between a
build warning and a customer finding a 404.
Finally, the navigation tree, docs/modules/ROOT/nav.adoc, an AsciiDoc
list of xrefs that becomes the site's sidebar:
* xref:index.adoc[Overview]
* xref:install.adoc[Install]
Commit the component:
git add docs
git commit -m "Add the Widget documentation component"
The commit matters more than it looks: Antora reads content from git, not from loose files. An uncommitted page doesn't exist as far as a normal build is concerned.
3. Create the playbook and build the site
The playbook repository is the site's recipe. Set it up next to widget/:
cd ..
mkdir docs-site && cd docs-site
git init
npm init -y
npm install @antora/cli@3.1 @antora/site-generator@3.1
Create antora-playbook.yml:
site:
title: Widget Docs
start_page: widget::index.adoc
content:
sources:
- url: ../widget
branches: HEAD
start_path: docs
ui:
bundle:
url: https://gitlab.com/antora/antora-ui-default/-/jobs/artifacts/HEAD/raw/build/ui-bundle.zip?job=bundle
snapshot: true
Reading it top to bottom: the site's start page is the index.adoc page of
the widget component; the content comes from the git repository at
../widget (a local path during development, an https:// URL in
production), reading the current branch (HEAD), with the component rooted
at docs/; and the look and feel comes from Antora's default UI bundle,
which is a separate artifact precisely so content builds never depend on a
frontend toolchain.
Build it:
npx antora antora-playbook.yml
Open build/site/index.html in your browser. You have a documentation site:
sidebar navigation from your nav.adoc, a component/version selector, and
your two pages — built from a git repository, by a command a CI runner can
execute.
4. Make the change that shows the point
Suppose both pages need the same warning about supported platforms. In a wiki you'd paste it twice and the copies would drift. Here, you write it once.
Create widget/docs/modules/ROOT/partials/supported-platforms.adoc:
WARNING: Widget 1.0 supports Linux (x86_64 and arm64) and macOS 13+.
Windows support is planned for 2.0.
Then pull it into install.adoc (and anywhere else) with one line:
include::partial$supported-platforms.adoc[]
The partial$ prefix is an Antora resource ID family; it says "resolve
this from the partials/ directory of this module." The same pattern gives
you example$ for code samples and image$ for figures, and it keeps
working when a page moves, because nothing is a relative file path.
Commit in widget/, rebuild in docs-site/:
cd ../widget
git add docs && git commit -m "Single-source the supported-platforms warning"
cd ../docs-site
npx antora antora-playbook.yml
Reload the page. The warning renders in place — and the day platform support changes, you'll edit one file and every page that includes it will be correct in the next build.
To see the safety net work, try breaking something: change a page's xref to
xref:intsall.adoc[] and rebuild. Antora logs an error naming the page and
the unresolved target. In the CI how-to
you'll promote that from a log line to a failed build.
What you learned
- A documentation component is a conventional directory in the product's
repository:
antora.ymlplusmodules/*/pages,partials/, andexamples/. - The playbook repository assembles components into a site; content teams and the docs platform stay decoupled.
- Antora reads content from git, which is what makes versions-from- branches possible later.
xref:andinclude::partial$...[]are the two AsciiDoc habits that pay rent immediately: validated links and single-sourced content.
Where next
- Wire the build into CI so the site publishes itself: Publish the site with GitHub Actions.
- Add a second documentation version the right way: Version your docs with branches.
- Understand what the build just did: How Antora assembles a site.