Everything the theme shows is data, and `app/app.config.ts` is where a site
states it. There is no second config file: the same `duxt` key carries the
theme, the documentation sources and the site's own links.

```ts [app/app.config.ts]
export default defineAppConfig({
  duxt: {
    title: 'my project',
    version: 'v1.4.0',
    sources: [{ path: 'docs' }]
  }
});
```

Every key and its default is in the
[configuration reference](/reference/configuration); the sources entry
has [its own page](/reference/sources).

## How your config merges

Your `duxt` object is merged over the layer's defaults key by key, and **an
array of yours replaces the layer's** rather than being appended to it. That
matters because Nuxt's own `app.config` merge does the opposite: it concatenates
arrays, which would leave you unable to remove a single navbar entry the layer
ships. So the layer ships no lists in `app.config` at all and merges them
itself.

The practical rule: override `footer.copyright` and `footer.legal` stays
untouched; declare `navigation` and the layer's one entry is gone.

## Two keys are read at build time

`sources` and `locales` decide the collections, the routes and the `hreflang`
links, and all three are settled before the first request. Changing either needs
a rebuild; everything else takes effect as soon as the config is reloaded.

## Some keys are generated, not written

`resolvedSources`, `layerVersion` and `layerRepository` appear in the config at
runtime and belong to the build. `resolvedSources` is the manifest the theme
actually reads — which collection serves which URL prefix — resolved from the
`sources` list you wrote. Writing any of the three by hand is overwritten.

## What the layer does not presume to know

`links`, `aside.links` and `footer.legal` ship **empty**. A repository, an issue
tracker, a community and an imprint each name a specific project, so a default
naming duxt's would hand your readers a "Star on GitHub" that stars somebody
else's work.

`sections` ships empty for the neighbouring reason: it names the top-level parts
of your documentation tree, and the layer cannot know what you called them. Set
it once your docs have sections; until then the row stays hidden and the sidebar
shows the whole tree.

```ts
sections: [
  { label: 'Guides', to: '/guides', icon: 'lucide:book-open' },
  { label: 'Reference', to: '/reference', icon: 'lucide:list' }
]
```

Write your own — as a plain string, or as a per-locale record if the site serves
several languages:

```ts
links: [
  {
    icon: 'simple-icons:github',
    to: 'https://github.com/you/your-project',
    label: { 'en-GB': 'Repository', 'de-DE': 'Repository' }
  }
]
```

::callout{type="warning" title="duxt.defaults.* is not yours to use"}
The layer's own i18n keys translate the defaults it ships. They are internal:
renaming one is not a breaking change, and i18n answers a missing key by
printing the key — so the break would be silent on your site. Use a literal, a
key of your own, or the record form above.
::

## The site's origin

duxt cannot guess the domain it will be served from, and four things need it:
`hreflang`, `canonical`, the sitemap and the Open Graph images. State it once,
where Nuxt already asks:

```ts [nuxt.config.ts]
i18n: { baseUrl: 'https://docs.example.com' }
```

or as `NUXT_PUBLIC_I18N_BASE_URL` in the deployment. The layer copies it to
`site.url`, which is where the SEO modules look. Left unset, each of them
degrades to relative output rather than inventing a domain — a relative
`canonical` still resolves, a guessed one is actively wrong. See
[SEO](/concepts/seo).