Configuration
Every key under duxt in app.config.ts — what it controls, and when it is read.
Everything below lives under duxt in your app/app.config.ts. How the merge
works, and why arrays replace rather than append, is in
Configuration.
Site
| Key | Default | What it controls |
|---|---|---|
title | none | The name in the navbar and in the SEO title |
logo | none | A wordmark replacing the icon-and-name pair — see below |
version | none | The badge beside it |
organization | none | Who publishes the site, for schema.org — see below |
locales | all seven | Which of the layer's languages this site serves |
breadcrumb | true | false drops the trail above the page title |
pageIcon | none | Icon for any page whose frontmatter sets none — a section's own wins |
packageManagers | pnpm, npm, yarn, bun | Which managers a command block offers, in that order |
requestSamples | seven of twelve | Which code samples the try-it client offers — see Request samples |
sampleLanguages | none | Extra Shiki grammars, for x-codeSamples in a language no sample names |
poweredBy | on | false drops the "Powered by duxt" line from the footer |
logo
| Field | Type | Notes |
|---|---|---|
src | string | The mark. Unset leaves the generic icon beside title |
srcDark | string | Swapped in by CSS under the dark class, not by script |
alt | text | Falls back to title |
Setting one is Brand your site.
organization
The Organization node search engines and AI summaries read to name a source.
Absent until you set it: duxt renders somebody else's documentation and does not
guess whose.
| Field | Type | Notes |
|---|---|---|
name | text | The publisher's name. Nothing is published without it |
url | string | Their site. Falls back to site.url |
logo | string | Absolute, or a path from the site root; square and 112px or more |
Navigation and links
A section entry is a link plus one field of its own:
| Field | Type | Notes |
|---|---|---|
pageIcon | string | Icon for pages in this section that set none. Overrides duxt.pageIcon; a page's own frontmatter still wins |
Useful where pages cannot carry an icon at all — an ADR's frontmatter is fixed
at title, description, status and date, so the decision log otherwise
renders without one.
| Key | Default | What it controls |
|---|---|---|
navigation | one entry | Navbar links; an entry with children becomes a dropdown |
sections | empty | The second navbar row — the top-level parts of the docs |
links | empty | Icon links on the right of the navbar |
aside | title only | title and links under the table of contents |
footer | empty | copyright and legal |
landing | one action | The page at / |
Most of these ship empty, for two different reasons. links, aside.links,
footer.legal, title, version and the landing copy name a specific project —
a repository, a community, a name, a release, a sentence about what it does — and
belong to whoever runs the site. sections names the parts of a documentation
tree, and the tree is yours: four tabs pointing at folder names the layer
guessed would lead nowhere. Until you set it, the row does not render and the
sidebar shows the whole tree, which is the right shape for docs that are not
split into sections.
One row per source. An entry belongs to the source whose URL prefix it lies
under, and the row shows the entries of the source the reader is in — so a site
with documentation at the root and something else at /demo writes one
sections list and each area draws its own part of it. A generated section
under an area (/demo/api) belongs to that area rather than being one of its
own. A site with a single source has one area, every entry is inside it, and the
row is exactly the list as written.
Landing
The page at / draws three bands, and each one is absent until its key is set.
| Key | Default | What it draws |
|---|---|---|
badge | none | The pill above the headline — text, or a badge object |
headline | none | The h1; falls back to title |
description | none | The paragraph under it, and the page's meta description |
actions | one, "Read the docs" | The hero buttons; an action with no to resolves to the first section |
command | none | A copyable install command under the buttons |
preview | none | A page of this site, embedded in a browser window |
features | empty | The card grid |
command is a plain string, not text: a shell command is the same in every
language, and one translated by mistake is one that does not run. The layer ships
none — it does not know what your project is called, the same reason links is
empty.
There is no closing call to action, deliberately. The hero's buttons are the call; repeating them under a card grid asks a reader who has just arrived to decide twice.
badge ships empty for the same reason as links: a pill above the headline
says something about the state of a project — "beta", "v2 is out" — and the layer
knows nothing about the state of yours. A string is the short form; the object
adds an icon, a colour and a destination.
badge field | Type | Notes |
|---|---|---|
label | text | Required. {version} is replaced with the site's version |
icon | string | Any Iconify name |
variant | string | default, secondary, outline, success, destructive |
to | string | Makes the whole pill a link |
external | boolean | The new tab |
badge: {
label: '{version} released',
icon: 'lucide:rocket',
variant: 'success',
to: 'https://github.com/acme/sdk/releases/latest',
external: true
}
preview is a live window, not a picture. It embeds a page of this site in a
browser frame the reader can scroll, navigate and switch the theme of without
leaving the landing page. The frame mounts only once the band scrolls into view,
and never during server rendering — an iframe in the initial HTML is a second
full page load competing with the first.
preview field | Type | Notes |
|---|---|---|
to | string | The page to embed; defaults to the first section |
height | string | Any CSS length. Default 32rem, 24rem under sm |
src | string | A screenshot INSTEAD of the live page |
srcDark | string | Serves dark mode; without it src serves both |
alt | text | The image's alt text, and the frame's accessible name |
The live frame loads the application a second time. A site that would rather not
pay for that sets src and gets the same window around a still image.
Link shape
| Field | Type | Notes |
|---|---|---|
label | text | Required |
to | string | A documentation path is localised; a URL is not |
icon | string | Any Iconify name, e.g. lucide:rocket |
description | text | Shown in a navbar dropdown |
external | boolean | The new tab and the arrow — never the routing |
children | DuxtLink[] | Turns a navbar entry into a dropdown |
variant | button variant | landing.actions only |
Every field marked text takes a literal, an i18n key or a per-locale record — see Localisation.
Sources
| Key | Read at | What it controls |
|---|---|---|
sources | build time | The documentation sources |
sourceOptions | build time | How those sources become URL prefixes |
versions | runtime | Overrides the derived versions, when they need labels or descriptions |
Both source keys have their own page. locales is the third
build-time key: changing any of the three needs a rebuild.
The feed
/rss.xml is empty until feed.path names a section:
feed: { path: '/changelog', title: 'my project — releases' }
Off by default on purpose. A feed is a list of things that happened, and a
reference page being edited is not an event — a site publishing every page edit
as an item teaches its readers to unsubscribe. Items are ordered by a page's own
date, falling back to the last commit that touched it, and only the default
version of each source contributes, so a versioned changelog does not repeat
every entry once per version.
The section it is usually pointed at is a
release history, whose pages carry a date each.
Generated, not written
| Key | Written by | Holds |
|---|---|---|
resolvedSources | the build | The manifest: which collection serves which prefix |
layerVersion | the build | duxt's own version, for the footer |
layerRepository | the build | duxt's own repository, for the footer |
Setting any of the three by hand is overwritten on the next build.