A **source** is a folder of Markdown: in this repository, or in another one, at
the current checkout or at named refs. The `sources` list is the only place they
are declared, and everything else is generated from it.

```ts [app/app.config.ts]
sources: [
  { path: 'docs', slug: 'acme' },
  { repo: 'acme/api', path: 'docs', refs: ['main', 'v2.0.0', 'v1.4.0'] }
]
```

Two repositories and three refs: five collections, the URL prefixes that serve
them, a version switcher, the redirect rules and the sitemap entries. None of it
is written by hand. Every field is in the [sources reference](/reference/sources).

## How it works

Content v3 already does the hard half. A collection source takes a repository
URL, a branch or tag and credentials, and Content downloads it and caches it by
hash — multi-repo, private repositories and reading from a tag all exist there.
duxt does not reimplement any of it.

What duxt adds happens at config load time. `content.config.ts` is executed
code, not a data file, so it can read the site's own `app.config.ts` and compute
its collections from that list — one collection per repository × ref, each with
an absolute `cwd`, a name derived from the slug, and the page schema the theme
needs. The same list is resolved a second time by the build into the
**manifest**: which collection serves which URL prefix, which ref is the
default, where each page came from. That manifest is what the theme reads, and it
is written back into the app config as `resolvedSources`.

## Why it's built this way

Declaring the collections by hand does not scale in the one direction
documentation actually grows: three versions across fourteen repositories is
forty-two declarations, and each release edits all fourteen. The shorthand keeps
the list the length of the number of projects.

The cost is that a source list expresses less than a hand-written collection
can. That is a deliberate trade: a consumer who needs something the shorthand
cannot say writes an own `content.config.ts` and takes over completely, because
Content merges the file from every layer with the later one winning.

## What falls out of it

Because a source names a repository, a ref and a folder, several features need
no configuration of their own: "Edit this page", the last-updated date and the
contributor list are all derived from it. Reading a **remote** source's history
costs a full clone, so it waits for `history: true` — a shallow clone would
report the tip's author for every file, which is wrong data rather than missing
data.