A duxt site is a Nuxt application. Anything that runs Nuxt runs it.

## Steps

:::steps
1. **Prefer static.** `nuxt generate` produces a folder of HTML — no server, no
   runtime cost, every page cached at the edge. It is the right default for
   documentation.

   ::package-managers{command="run generate"}
   ::

   `nuxt build` produces a Node server, which you need only if a page must react
   to a request.

2. **Give the build what it needs.** Node 24 (the database is read through
   `node:sqlite`, so no native driver is installed), network access to any remote
   source, and a token for the private ones.

3. **Set the origin.** `NUXT_PUBLIC_I18N_BASE_URL`, or `i18n.baseUrl` in the
   config. Without it `hreflang`, `canonical`, the sitemap and the social cards
   fall back to relative output.

4. **Set an OG image secret if you deploy more than one instance.**
   `NUXT_OG_IMAGE_SECRET`, generated once. Without it each build signs image URLs
   with a secret of its own, and a card signed by one instance is rejected by the
   next.

5. **Schedule a rebuild.** A site reading another repository picks up its changes
   when it builds, not when they are pushed.

:::

## Why there is no runtime refresh

Content downloads a remote repository at build time and compiles it into the
database the build ships. Refreshing that at runtime would mean rebuilding the
database inside a live server — Content offers no supported path for it, and the
only route available is the same client database the search reads. A scheduled
rebuild, or one triggered from the source repository, keeps the deployment
immutable and the content reproducible.

## When a build says `database is locked`

Content keeps its parse cache in `.data/content/contents.sqlite`, and a build
the kernel or a `Ctrl-C` left behind can go on holding it. Every following build
then fails with `database is locked` — a message that names neither the file nor
the process.

duxt puts that database into [WAL mode](https://www.sqlite.org/wal.html) before
Content opens it, which lets a reader and a writer coexist and removes the
everyday version of this outright. What it cannot remove is a second process
still running:

```bash
pgrep -af 'nuxt (build|dev|generate)'   # the orphan, if there is one
kill <pid>
```

If nothing turns up and the error persists, delete `.data/content/` — it is a
cache, and the next build rebuilds it from the sources.

## What the site serves besides pages

`/llms.txt`, `/llms-full.txt`, any page's `.md` source, `/mcp`, `/sitemap.xml`,
`/robots.txt` and — once configured — `/rss.xml`. The full list with its caveats
is in the [endpoints reference](/reference/endpoints).

## Checklist

- [ ] `nuxt generate` completes with no error from the validator
- [ ] The origin is set in the deployment, not only locally
- [ ] `/sitemap.xml` lists absolute URLs on the real domain
- [ ] A rebuild is scheduled, or triggered from every source repository
- [ ] `NUXT_OG_IMAGE_SECRET` is set if more than one instance serves the site