Skip to content
duxt

Sources

The fields of a source entry, its refs, and the options that shape the URLs.

duxt.sources is a list of source entries; duxt.sourceOptions says how they become URLs. Both are read at build time. What they generate, and why, is in Sources.

A source entry

FieldTypeNotes
pathstringFolder holding the Markdown, relative to the repository root
repostringowner/name or a git URL. Omitted means this repository
refsref listRefs to publish as versions. Omitted means the current checkout
versionstringThe version this source is, where no ref names one
labeltextShown in the switcher and used in the URL; defaults to the ref
slugstringThis source's URL segment. Naming one claims it — see below
statusstatusLifecycle of every version this entry publishes
origin{ repo, ref? }Where pages read off disk live, for links back to them
historybooleanRead this source's git history
localeslocale listLanguages this source is available in — see below
generatedsection listArtefacts published as pages beside the Markdown — see below

Two fields are easy to confuse and expensive to get wrong:

  • repo downloads, origin only links. Naming your own repository in repo has the build clone the checkout it is already standing in.
  • history costs a full clone. Content clones a remote repository with --depth 1, so its checkout holds one commit and every file looks as if the person who cut the tip wrote it — wrong data, not missing data. Turning this on unshallows the clone once. A source read off disk is a full checkout already and is read regardless.

slug claims a segment. A source is normally given one only once the list names more than one repository — all or nothing, across the whole site. A source that writes its own slug is served under it either way, and the sources that write none stay where they are, which is what lets one thing sit at /demo beside documentation that keeps the root.

Refs

A bare string is a branch. A tag has to say so: git keeps branches and tags in separate namespaces, and asking for a tag under refs/heads fails the build with Could not find refs/heads/….

refs: [
  'main',                                     // a branch
  { branch: 'next', status: 'upcoming' },     // the same, with a lifecycle
  { tag: 'v2.0.0', label: 'v2' },             // a tag
  'latest'                                    // the newest semver tag, resolved at build
]

'latest' is reserved. A branch genuinely called latest needs the { branch } form.

Locales

Omitted, the source has one language and one collection. Listed, each entry becomes a collection of its own.

locales: [
  'en-GB',                                              // the default: docs/ itself
  'de',                                                 // docs/de/
  { locale: 'fr', path: 'translations/fr' },            // somewhere else in this repo
  { locale: 'es', repo: 'acme/docs-es', path: 'docs' }  // another repository
]

A string is a folder inside the source's path. The object form overrides path, repo and ref for that language alone — which is what lets a translation live in a repository of its own, with its own maintainers and its own release schedule.

The default locale is the tree in path itself and takes no folder. Which one that is comes from sourceOptions.defaultLocale, and it has to agree with i18n.defaultLocale — the build fails when they differ, because content.config.ts resolves the collections without access to the Nuxt config.

A ref may carry its own locales, overriding the source's exactly as status does. That is the usual shape: the current version is translated, the ones behind it are not.

refs: [
  { tag: 'v2.0.0' },                     // inherits the source's locales
  { tag: 'v1.0.0', locales: ['en-GB'] }  // original only
]

Name a folder by LANGUAGE where a region adds nothing: docs/pt/ serves both pt-PT and pt-BR, because a page falls back through its base language. The same rule the layer's own locale files follow.

Status

ValueMeans
upcomingNot released yet — may still change
currentThe documentation to read
maintainedOlder, still supported
deprecatedOlder, and the reader should upgrade
eolDead — warned about, and out of the sitemap

What each one costs a page is in URLs and versions.

Generated sections

generated lists artefacts that are not Markdown and the type that reads each one into pages. What the mechanism is, and the two policies a type answers, is in Generated sections; the fields below are the same whichever type reads them.

FieldTypeNotes
typestringThe registry key of the type — changelog, openapi, your own
pathstringThe artefact, relative to the source's own root
labelstringThe navbar entry, and — slugified — the URL segment
slugstringOverrides the segment the label would produce
optionsobjectThe knobs that type offers; each type validates its own
versionsversion listThe versions of this artefact — see below
localesRecord<string, string>An artefact per locale, read by a per-locale type only
navigationplacement'sections' (the default), 'navigation', or false
iconstringFalls back to the type's own

path is a path and never a URL. For a source Content clones it is relative to the root of that checkout, so the artefact travels with the version it belongs to — one rule in both directions. An arbitrary location would let an artefact be fetched from anywhere and reopen the build-time-network question sources has already closed.

label is a plain string, not a translated text, for the same reason a version's label is: a translated text is not a stable URL.

A section with versions of its own

A version is normally a checkout: list refs on the source and every section it carries is published once per ref. An API is usually not kept that way — openapi/v1.yaml sits beside openapi/v2.yaml in one repository, versioned by file — and without this key the two are two unrelated sections with two entries in the navbar.

generated: [
  {
    type: 'openapi',
    label: 'API',
    path: 'openapi/v2.yaml',
    versions: [
      { version: 'v2', path: 'openapi/v2.yaml' },
      { version: 'v1', path: 'openapi/v1.yaml', status: 'deprecated' }
    ]
  }
]
FieldNotes
versionShown in the switcher and used in the URL
pathThe artefact this version reads; defaults to the declaration's
localesPer-locale artefacts for this version
statusLifecycle of this version — deprecated, eol, upcoming
defaultServed without a version segment. Defaults to the first entry

The default is served at /api, every other version under its own segment (/v1/api), and the switcher offers them exactly as it offers a source's refs — with the deprecation banner, the noindex and the canonical that go with a version that is not the current one.

Declared here rather than as two sources, and that is the design rather than a convenience: two sections are offered as versions of one another only when one declaration produced them, and a source always publishes a documentation tree — so a source per API version would publish the prose twice.

Never beside a source versioned by refs. Both want the same segment of the URL, and the build says so instead of nesting them. A global type — a changelog — refuses them too: it publishes one history at a version-neutral URL, so a list of versions is a contradiction rather than a shape to resolve.

Which version is which

Three things are called a version around a reference page, and only two of them are duxt's:

  • The version in the URL and the switcher — a ref, or a version declared as above. It is what the badge in the header shows: which variant you are reading.
  • duxt.version — the site's own string, shown in that badge only where there is nothing to switch between.
  • info.version of an OpenAPI document — what the document says about the API it describes. It is drawn on the reference's own page, labelled API version, and never in the badge: a badge is the switcher's trigger, and a document's own claim is not somewhere you can switch to.

They often carry the same number, because a repository that tags v2.0.0 usually writes 2.1.0 in the document it tagged. They are still different facts, and duxt derives neither from the other.

options is opaque to everything but the type that reads it — a granularity means something to a changelog and nothing to an API reference. A key the type does not know fails the build rather than being ignored, because a misspelled option is a site quietly not getting what it configured.

Source options

FieldDefaultWhat it does
showRepooffForce a repository segment with a single repository
showVersionoffForce a version segment with a single version
defaultRefthe first refThe ref served without a version prefix
defaultLocalethe first localeThe locale served from path itself, with no folder

The resolved manifest

The build turns the list above into duxt.resolvedSources, and that is what the theme reads. useDuxtCollection() exposes it; each entry carries the collection name, the URL prefix, repo, version, isDefault, locale, isDefaultLocale, status, the repository and ref the pages came from, and whether its history was read.

The locale is deliberately absent from prefix: i18n puts it in front of the path already, so every language of one source shares a prefix and differs only by collection.

Was this page helpful?