How to Run the ID Allocation Server

The ID allocation server is a standalone package (@antora-tracer/id-server), a companion service to the Antora extension and CLI — not part of either.

The remote next-id feature needs an allocator service to request IDs from. This guide runs the standalone server that implements it, from source or in Docker.

Prerequisites

  1. Node.js 22.5 or later — the server uses the built-in node:sqlite module

  2. The @antora-tracer/id-server package, or a checkout of the repository

Start the server

From the repository:

cd id-server
npm install
npm run build
npm start -- ./config.yml

Once published, run the binary directly:

npx @antora-tracer/id-server ./config.yml

The server listens on port 8080 by default.

Run with Docker

A prebuilt image is published to the GitHub Container Registry on every release:

docker pull ghcr.io/rattermeyer/id-server:latest

The repository also ships a Compose file in id-server/ that builds the image from source, for local development. The image serves with node:22-alpine, and config.yml is mounted read-only at /config/config.yml.

  1. Create the config, secret, and data files:

cd id-server
cp config.example.yml config.yml
cp .env.example .env
mkdir -p data
  1. Start the stack, from the published image or built from source:

docker run -d --name id-server --env-file .env -p 8080:8080 \
  -v ./config.yml:/config/config.yml:ro -v ./data:/data \
  ghcr.io/rattermeyer/id-server:latest

# or, build from source:
docker compose up -d --build

The SQLite database persists in the host ./data directory.

Add a project key

Set adminToken in config.yml, then manage projects at runtime with the projects command (see the Manage projects section below). No restart or image rebuild:

antora-id-server projects add acme --token acme-secret \
  --endpoint http://localhost:8080 --admin-token ...

The tokens config only seeds projects on first boot. After that, changes go through the admin API.

Back up

tar czf id-server-backup.tgz ./config.yml ./data

The entire persistent state is the single ./data/ids.sqlite file. Because token values are ${VAR}-interpolated, config.yml holds no secrets.

Verify

curl http://localhost:8080/next-id?prefix=REQ
# {"id":"REQ-001"}

Configure the server

Create a config.yml:

port: 8080                       # optional, default 8080
db: ./ids.sqlite                 # optional, SQLite file
adminToken: ${ADMIN_TOKEN}       # optional, enables the project admin API
tokens:                          # seeds initial projects (tenant -> token)
  acme: acme-secret
  beta: beta-secret
prefixes:                        # per-prefix allocation config
  REQ:
    width: 3                     # minimum padding (default 3)
    start: 55                    # first ID number (default 1)
  ARC: 4                         # shorthand = width only
tenantPrefixes:                  # optional per-tenant overrides
  beta:
    REQ:
      start: 1000                # beta's REQ sequence starts here
      width: 4
  • tokens maps each bearer token to a tenant, seeding the initial project set on first boot. Each tenant gets an independent ID sequence.

  • When no tokens and no adminToken are configured, every request is attributed to a default tenant.

  • When projects are configured, a request without a valid token — absent, malformed, or unrecognized — is rejected with 401.

  • adminToken enables the project admin API. With it set, a valid project token is always required, even before any project is added.

  • prefixes sets the minimum zero-padding width per prefix, defaulting to 3. IDs grow past the width rather than truncating.

  • A prefix’s start sets the first ID the server allocates for it, defaulting to 1. A team with existing IDs can set start to continue from their sequence instead of colliding at 001.

  • tenantPrefixes overrides prefixes per tenant and prefix, falling back to the global prefixes value and then to width 3 / start 1. Each tenant’s counter is still independent.

  • Tenants that reuse the same prefix still emit duplicate IDs if their start ranges overlap and the namespaces ever merge. Assign non-overlapping start ranges in tenantPrefixes when two tenants share a prefix.

  • Token values support environment-variable interpolation, so secrets stay out of the file.

  • Both the server and the CLI load a .env file from the working directory at startup, so you can keep the token there instead of exporting it.

Manage projects

The server runs in one of two modes:

  • Single team — no tokens and no adminToken. Every request shares one default tenant with no authentication.

  • Multi team — an adminToken is configured. Each project has its own token and counter, managed at runtime.

With adminToken set, manage projects with the projects subcommand:

antora-id-server projects list                           --endpoint http://localhost:8080 --admin-token ...
antora-id-server projects add acme --token acme-secret   --endpoint http://localhost:8080 --admin-token ...
antora-id-server projects update acme --token new-secret --endpoint http://localhost:8080 --admin-token ...
antora-id-server projects remove acme                    --endpoint http://localhost:8080 --admin-token ...

Changes take effect immediately — no restart. The endpoint and admin token also read from the ID_SERVER_ENDPOINT and ID_SERVER_ADMIN_TOKEN environment variables. Project tokens are stored hashed; list shows tenant names only.

Seed the server from existing IDs

If your project already has IDs in the local files (for example, REQ-001 through REQ-054), seed the server so it continues from REQ-055 instead of colliding at REQ-001.

Generate a seed file with the seed command:

npx antora-tracer seed -i docs/ -o seeds.yml

For a project spread across multiple repositories, point the command at the Antora playbook instead:

npx antora-tracer seed antora-playbook.yml -o seeds.yml

The output is a prefixes: map with a numeric start value per prefix. Merge that prefixes block into the server’s config.yml prefixes section.

The seed is a one-time snapshot. Re-run it before pointing new clients at the server if items were added since the last export.

Point the client at the server

In the client’s traceability.yml:

idAllocation:
  endpoint: http://localhost:8080
  token: ${ID_ALLOC_TOKEN}

Run antora-tracer next-id --prefix REQ and it requests the next ID from the server instead of scanning local files.

Verify

curl http://localhost:8080/next-id?prefix=REQ
# {"id":"REQ-001"}

curl http://localhost:8080/next-id?prefix=REQ
# {"id":"REQ-002"}