Versioning and Prerelease

This content was generated with the assistance of AI and should be verified against the official documentation of each tool before being relied on in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

This page was written against Antora 3.2.1 and checked on 2026-10-26. Every example was built with that version except where the text says otherwise. A component version in Antora is the pair of a component name and a version, and almost everything about a versioned site (the version selector, the URLs, the target of an xref that names no version) follows from how that version is defined, sorted and classified as stable or prerelease.

What a version is and why it matters

Antora does not understand releases; it only understands git references (branches and tags) that contain a component version descriptor, antora.yml. The version key of that descriptor, together with name, identifies one component version. Antora uses the version to:

  • sort the component versions of a component,

  • find the latest version of a component,

  • build the version segment of published URLs (/acme/2.0/index.html),

  • label the entry in the component version selector and the page version selector of the UI,

  • resolve the version coordinate in resource IDs (2.0@acme::index.adoc).

Several pieces of the same idea are kept apart on purpose. The actual version is the value of version. The prerelease marker, the display version and the symbolic version each override one default behaviour of the actual version and nothing else, as the following table (derived from the Antora version-facets page) shows.

Facet In resource IDs Sorting and routing Shown in UI menus In URLs

Actual version (version)

Yes

Yes

Yes, unless replaced

Yes, unless replaced

Prerelease (prerelease)

No

Yes

Yes, appended to the version

No

Display version (display_version)

No

No

Yes

No

Symbolic version (latest_version_segment)

No

No

No

Only for the latest version

Symbolic prerelease version (latest_prerelease_version_segment)

No

No

No

Only for the latest prerelease

Where the version comes from

The version key can be written in the descriptor stored in each git reference or, as a fallback, on the content source in the playbook. When both exist, the descriptor wins. If you want the playbook to control the version, leave the key out of antora.yml. The accepted forms are the same in both places.

Form Example Meaning

Named identifier

version: edge

Any value that is not semantic. Sorted before semantic versions.

Semantic identifier

version: '2.5'

An integer, or a string that starts with an integer and contains a dot. A leading v is allowed and ignored when sorting. Quote values that look like numbers so YAML keeps them as strings.

Versionless

version: ~

The tilde (or null) defines a component version with an empty version. No version segment is added to its URLs.

Refname

version: true

The short name of the branch or tag becomes the version. Forward slashes are replaced with hyphens.

Refname projection

A map of patterns to replacements

The version is derived from the refname. Antora uses the first pattern that matches and falls back to the refname if none does.

A literal value may contain letters, digits, periods, underscores and hyphens, and must not contain spaces, forward slashes or the characters &, < and >. Use lowercase letters for portability between web servers. A fixed value on a playbook content source is only sensible when the source matches a single reference; otherwise use true or a projection.

A projection is a map from a glob (with the same syntax as the branches and tags patterns) to a replacement. Groups in parentheses can be named with ?<name> and referenced as $<name>, or referenced by position ($1), and $& is the whole refname. The next playbook takes versions from tags named v1.0.0, v1.1.0 and v2.0.0 and from a release branch, none of which has a version key in its antora.yml.

antora-playbook.yml
site:
  title: Widgets Docs
  url: https://docs.example.com
content:
  sources:
  - url: ./tagged
    branches: release/*
    tags: v*
    version:
      'v(?<major>*).(?<minor>*).*': $<major>.$<minor>
      'release/(*)-rc': $1

The branch release/3.0-rc has prerelease: -rc.1 in its descriptor. The result, printed by the small extension shown later on this page, is:

component widgets: latest=2.0 latestPrerelease=3.0
  3.0    displayVersion="3.0-rc.1" prerelease="-rc.1" url=/widgets/3.0/index.html
  2.0    displayVersion="2.0" prerelease=undefined url=/widgets/2.0/index.html
  1.1    displayVersion="1.1" prerelease=undefined url=/widgets/1.1/index.html
  1.0    displayVersion="1.0" prerelease=undefined url=/widgets/1.0/index.html

Replacing the projection with version: true on the same sources produced the versions v2.0.0, v1.1.0, v1.0.0 and release-3.0-rc (the slash became a hyphen), and the URL /widgets/release-3.0-rc/index.html. Branch versioning (one long-lived branch per release, such as v1.0.x) and tag versioning (one tag per release) both work; what matters is only that each reference carries a descriptor, and that the name and version pair is unique. == How versions are sorted

Antora only looks at the version key when it sorts, never at display_version or the URL. It recognises three schemes.

Scheme Matches Examples

Semantic

A string that starts with a number (optionally preceded by v) and contains at least one dot, or an integer

30, 2.4, v90.3

Named

Everything that is neither semantic nor the reserved empty value

edge, z4

Versionless

~ or null

(empty)

The ordering rules are:

  • A versionless component version sorts first, before named and semantic versions.

  • Named versions come before semantic versions and are sorted in reverse alphabetical order. Uppercase letters sort before lowercase ones and are not recommended.

  • Semantic versions come last, in descending order, using semantic-versioning rules and ignoring a leading v.

For example, the versions v2.5, 4.0, 3.9, utopia and vivid appear in the order vivid, utopia, 4.0, 3.9, v2.5. Components themselves are sorted alphabetically by title in the UI model (site.components), falling back to the name when there is no title.

The latest version of a component is the first version in that sorted list which is not a prerelease. If every version is a prerelease, the first prerelease is the latest. A versionless component version is always the latest version, or the latest prerelease if it sets prerelease. The latest version is exposed to the UI as the latest property of the component.

A named version therefore beats every number. In this build, a branch with version: edge next to the semantic versions 1.0, 2.0, 2.5 and a prerelease 3.0 takes the lead:

component acme: latest=edge latestPrerelease=none
  edge   displayVersion="edge" prerelease=undefined url=/acme/edge/index.html
  3.0    displayVersion="3.0-beta.2" prerelease="-beta.2" url=/acme/3.0/index.html
  2.5    displayVersion="2.5" prerelease=undefined url=/acme/2.5/index.html
  2.0    displayVersion="2.0" prerelease=undefined url=/acme/2.0/index.html
  1.0    displayVersion="1.0" prerelease=undefined url=/acme/1.0/index.html

Two details of this output are worth knowing. edge is the latest version, so inbound references that name no version land on it. And latestPrerelease is none because 3.0 sorts after edge: the latest prerelease only exists when a prerelease sorts ahead of the latest stable version.

Prerelease

The prerelease key marks a component version as not yet stable without changing its identity. It accepts an identifier (a non-empty string such as -rc.3, .alpha.2, -M1, SNAPSHOT or Beta) or true. Set it to false, or remove it, when the version is released; the version, its URLs and the references that point to it do not change.

antora.yml
name: acme
title: Acme
version: '3.0'
prerelease: -beta.2
nav:
- modules/ROOT/nav.adoc

What Antora does with a prerelease:

  • It computes a prerelease version. If the identifier starts with a hyphen or a dot it is appended directly (3.0 and -beta.2 give 3.0-beta.2); any other identifier is appended after a space (4.0 and Beta give 4.0 Beta). This value is used for sorting and, unless display_version is set, is shown in the UI menus. With prerelease: true the version is shown unchanged.

  • It skips the version when picking the latest version, unless every version of the component is a prerelease.

  • It does not route a reference to it when the reference gives no version. Such references go to the latest stable version.

In the previous listings 3.0 appears with the display version 3.0-beta.2 and the URL /acme/3.0/index.html, so the default URL does not tell readers that it is a prerelease. The prerelease key never changes a URL by itself; only latest_prerelease_version_segment, described below, does.

Display version

display_version changes only what the UI menus show. It may contain spaces, uppercase letters and symbols, such as '5.6 EOL' or 3.0 Beta. It is never used in resource IDs, sorting or URLs, and when both display_version and prerelease are set the display version is shown but the computed prerelease version still decides the order. Versionless component versions are labelled default in the menus unless a display version or a prerelease identifier says otherwise.

Latest version segments

By default the version segment of a URL is the actual version, so the latest version is not recognisable from the address. Two playbook keys under urls replace the segment for the latest version and the latest prerelease of every component. Both keys apply to the whole site and cannot be set in antora.yml.

Key Effect

latest_version_segment

The symbolic version used in place of the actual version in URLs of the latest version of each component, for example current or stable.

latest_prerelease_version_segment

The same for the latest prerelease, for example next or unstable. It only applies when the component also has a stable version; a component made only of prereleases uses latest_version_segment for its latest version.

latest_version_segment_strategy

Chooses between replacing the URL and redirecting (see below).

The values follow the same character rules as version. The value cannot be null, and it can only be an empty string with the replace and redirect:to strategies. With an empty string, the latest version is published with no version segment at all. It is not applied to versionless component versions.

Replace (the default)

If the playbook sets a symbolic version and no strategy, Antora uses replace at run time: the latest version is published only under the symbolic URL. The playbook below was built with the versions 1.0, 2.0, 2.5 and the prerelease 3.0 from the earlier example, without the edge branch.

antora-playbook.yml
site:
  title: Acme Docs
  url: https://docs.example.com
content:
  sources:
  - url: ./acme
    branches: [v1.0.x, v2.0.x, v2.5.x, v3.0.x]
urls:
  latest_version_segment: current
  latest_prerelease_version_segment: next
component acme: latest=2.5 latestPrerelease=3.0
  3.0    displayVersion="3.0-beta.2" prerelease="-beta.2" url=/acme/next/index.html
  2.5    displayVersion="2.5" prerelease=undefined url=/acme/current/index.html
  2.0    displayVersion="2.0" prerelease=undefined url=/acme/2.0/index.html
  1.0    displayVersion="1.0" prerelease=undefined url=/acme/1.0/index.html

The generated site contains acme/1.0, acme/2.0, acme/current and acme/next; there is no acme/2.5 directory. When 2.6 is released and becomes the latest version, 2.5 moves to acme/2.5 and current points to 2.6. Because current is not a version, bookmarks to it stay valid but the content behind it changes. Setting latest_version_segment: '' instead published the latest version at /acme/index.html, and the other versions under their numbers.

Redirect strategies

redirect:to and redirect:from keep both addresses alive by generating temporary (302) redirects. They need a redirect facility other than the default static, because only a web server can answer with a redirect.

Strategy Behaviour

replace

Default. The actual version is replaced by the symbolic version; no redirect rules are generated.

redirect:to

The page is published under the symbolic URL, and the URL with the actual version redirects to it. Without a redirect facility it becomes replace. Nothing happens for an empty version.

redirect:from

The page stays under the actual version, and the symbolic URL redirects to it. The symbolic version cannot be empty with this strategy. It is ignored when the facility is static.

The next playbook fragment used redirect:to with the Netlify facility, and Antora wrote a _redirects file at the site root:

urls:
  latest_version_segment: current
  latest_version_segment_strategy: redirect:to
  redirect_facility: netlify
/acme/2.5/* /acme/current/:splat 302!

In that build the prerelease 3.0 remained at /acme/3.0/ because no latest_prerelease_version_segment was set.

Branches to versions to URLs

The diagram summarises what the builds above did. Each branch or tag contains a descriptor; Antora resolves a version, sorts the versions, marks the latest and the latest prerelease, and finally decides the version segment for the URL.

flowchart LR B1["branch v1.0.x"] --> V1["1.0"] B2["branch v2.0.x"] --> V2["2.0"] B3["branch v2.5.x"] --> V3["2.5 (latest)"] B4["branch v3.0.x with prerelease"] --> V4["3.0 (latest prerelease)"] V1 --> U1["/acme/1.0/"] V2 --> U2["/acme/2.0/"] V3 --> U3["/acme/current/"] V4 --> U4["/acme/next/"]

The 3.2 change: versionSegment

The Antora 3.2 release notes (issue 1006) say that the content classifier now uses the versionSegment property of a component version, when present, instead of the version in the output path and URL of pages, and that it sets a dynamic activeVersionSegment property telling which segment is in use. These are properties of the component version in the content catalog that extensions work with; the official documentation does not list versionSegment among the keys of antora.yml. A site that uses no extension setting it is unaffected, and latest_version_segment and its strategies work as described above. An extension that builds URLs by hand should read activeVersionSegment rather than version, because the latest version is published under the symbolic segment.

The version also appears in resource IDs. A reference that gives no version resolves to the latest version of the target component, but never to a prerelease unless every version is a prerelease. A reference can pin a version with the coordinate before the component, and a versionless target can be addressed with _. The page that follows gives the full grammar; this build is only the effect on versions. A page with the two references

* xref:widgets::index.adoc[Latest stable (no version)]
* xref:3.0@widgets::index.adoc[Pinned to the prerelease]

produced links to ../widgets/2.0/index.html for the first and ../widgets/3.0/index.html for the second, with 3.0 being a prerelease. See Resource IDs and Xrefs for the complete syntax.

Printing the versions Antora sees

The listings in this page come from a few lines of extension code. It registers for the contentClassified event, when the content catalog already holds the sorted component versions.

print-versions.js
module.exports.register = function () {
  this.once('contentClassified', ({ contentCatalog }) => {
    for (const component of contentCatalog.getComponents()) {
      console.log(`component ${component.name}: latest=${component.latest.version || '(empty)'} ` +
        `latestPrerelease=${component.latestPrerelease ? component.latestPrerelease.version : 'none'}`)
      for (const cv of component.versions) {
        console.log(`  ${(cv.version || '(empty)').padEnd(6)} displayVersion=${JSON.stringify(cv.displayVersion)} ` +
          `prerelease=${JSON.stringify(cv.prerelease)} url=${cv.url}`)
      }
    }
  })
}

Enable it with antora.extensions in the playbook or --extension ./print-versions.js on the command line. See Antora Extensions for the extension API.

Pocket Units

Pocket Units keeps one branch per release in its documentation repository. The branches v1.0 and v2.0 each carry an antora.yml with name: pocket-units and their own version, and a second repository holds the versionless component shared, which declares version: ~. Building these with the default settings produced

pocket-units/1.0/index.html
pocket-units/2.0/index.html
shared/style-guide.html

The shared component has no version segment, as the rules require. With latest_version_segment: current, the pages of 2.0 would move to pocket-units/current/. To publish a 3.0 preview without it becoming the default target of references, add a v3.0 branch with prerelease: -beta.1, and optionally publish it at next with latest_prerelease_version_segment. This 3.0 preview was not built for Pocket Units; the acme builds above show the same behaviour.

Pitfalls and notes

  • A numeric-looking version must be quoted in YAML (version: '2.0'); an unquoted 2.0 is a number and 1.10 would become 1.1.

  • A named version such as edge, main or next sorts before every number and becomes the latest version. Keep named branches for a component that has only named versions, or give the development branch a semantic version with prerelease.

  • The version is not allowed to contain /. A projection or version: true converts slashes to hyphens, so release/3.0 becomes release-3.0.

  • prerelease does not change URLs. Use latest_prerelease_version_segment if you want an address that reveals it.

  • The redirect:to and redirect:from strategies are silently inactive with the default static facility. Set redirect_facility to netlify or nginx and deploy to a host that honours the generated file.

  • Changing latest_version_segment moves published URLs. Treat the segment as a stable public name.

  • The latest version is computed per component, so each component of a site has its own current version.