Skip to content

Configuration ​

Site configuration lives in two optional files: luaudocs.toml for settings and .luaudocs/custom.css for styling. Without them, dev and build run on defaults.

Scaffolding your project ​

bash
luaudocs init

init writes luaudocs.toml (auto-detecting [repo] url and any non-main default branch from git), user-owned starter pages (index.md, guide/, custom.css), and .github/workflows/docs.yml for GitHub Pages when missing.

Which files are yours ​

Everything you author lives at the top of .luaudocs/:

PathOwner
guide/, public/, custom.cssYours. Scaffolded once by init and never overwritten.
index.mdYours once you remove the # Generated by luaudocs marker (see below).
api/, .vitepress/Tool-owned. Cleaned and regenerated on every build.
package.json, changelog.md, public/llms*.txt, public/docmodel.jsonRegenerated in place on every build.
.gitignoreCreated once when missing.

Do not edit generated files

If luaudocs.toml and custom.css can't express what your docs need, open an issue instead of editing files inside api/ or .vitepress/. Future builds overwrite both directories.

Claiming the landing page without running init

When index.md is missing, builds generate one from your README.md (or a default hero) with # Generated by luaudocs on line 1. init replaces a still-marked file with its starter hero. Delete that marker line to claim index.md so neither build nor init overwrites your edits.

luaudocs.toml ​

All keys are optional. Commented entries show advanced options:

toml
title = "My Library"                  # defaults to the project folder name
description = "One-line tagline"      # site description / meta tag

[source]
entries = ["src"]                     # module roots (dir with init.luau, or a file; [] = guide-only)
# include = ["**/*.luau"]             # only document modules matching these globs
# exclude = ["**/*.spec.luau"]        # drop matching modules from the docs
# projectFile = "my.project.json"     # Rojo project mapping the instance tree (default: default.project.json)
# [source.aliases]                    # runtime require aliases (@lute, @std, and @lune are built in)
# pkg = "https://pkg.example/docs"    # links `@pkg/x` and its types to <base>/x
# dep = { url = "https://dep.example", model = "https://dep.example/docmodel.json" }  # links types to their exact entries
# lune = false                        # true keeps an alias unlinked, false drops a built-in one

[repo]                                # "view source" + edit links + GitHub icon
url = "https://github.com/you/repo"   # (init fills this in from your git remote)
branch = "main"

# [site]                              # branding (paths live in .luaudocs/public/)
# siteTitle = "Short Name"            # navbar text (defaults to title), or false for logo-only
# logo = "/logo.svg"                  # header logo, or { light = "…", dark = "…" }
# favicon = "/favicon.ico"
# ogImage = "/og.png"                 # social-preview image (og:image / twitter:card)
# footer = { message = "MIT", copyright = "© you" }  # shown on pages without a sidebar

# [[site.nav]]                        # header navbar (unset: Guide / API / Changelog as applicable)
# text = "Guide"
# link = "/guide/getting-started"
# activeMatch = "^/guide/"            # routes that mark the entry current (default: its link alone)
# [[site.nav]]                        # nest [[site.nav.items]] under an entry for a dropdown
# text = "API"
# link = "/api/"

# [[site.head]]                       # extra head tags on every page (analytics, verification)
# tag = "script"
# attrs = { defer = "true", src = "https://plausible.io/js/script.js", "data-domain" = "docs.example.com" }
# content = "..."                     # inline body, for tags that carry one

[api]
includePrivate = false                # render _members and @private (badged)
linkRobloxTypes = true                # link Roblox classes/enums/datatypes to creator docs
# reportUndocumented = true           # warn on every public member, class, and type with no doc comment

[docs]
# dir = ".luaudocs"                   # site root (your content + the generated machinery)
url = "https://docs.example.com"      # published URL: sitemap.xml + derived base path
# changelog = false                   # opt out of the CHANGELOG.md -> /changelog page
# includeReadme = true                # keep a README include fresh for your landing page (see below)
# llms = false                        # opt out of llms.txt + llms-full.txt
# model = true                        # publish public/docmodel.json, so other sites can link into this one

Unknown keys fail validation so typos can't silently disable settings.

Key details:

  • Base path. A path in [docs] url (user.github.io/repo/) becomes the site's base. See Deploying.
  • AI tooling. build writes public/llms.txt and public/llms-full.txt for deployed sites. Setting llms = false disables those two files without affecting the repository-root llms.txt generated by luaudocs llms.
  • The API sidebar. LuauDocs derives the API sidebar automatically from public access paths with no configuration. See How It Works.
  • Documentation coverage. [api] reportUndocumented = true emits an undocumented warning for each public member, class, or exported type without a doc comment (Widget:refresh), which fails luaudocs build --strict in CI. Private items and re-exports are excluded.
Putting your README on a custom landing page

Without a custom index.md, builds already render README.md as your landing page. Set includeReadme = true when you maintain a custom index.md and want to embed .vitepress/generated/readme.md (with moonwave-hide-before/after-this-line stripped) via a VitePress @include: ./.vitepress/generated/readme.md comment. Relative links in the README are rewritten to doc pages or [repo] GitHub URLs.

Source aliases ​

Requires through an alias not in .luaurc (require("@lute/fs")) resolve as external runtime modules instead of emitting require-unresolved. Re-exporting one renders a property showing the require expression, and types accessed through it (fs.File) link to <base>/<module>. Lute (@lute, @std) and Lune (@lune) are built in. Use [source.aliases] to register custom aliases or override built-in ones (lune = false drops a built-in alias, and alias = true marks an alias external without linking). .luaurc aliases always take precedence.

When a dependency publishes its doc model ([docs] model = true writes public/docmodel.json, such as luaudocs.kohl.gg/docmodel.json), configure [source.aliases] with { url, model }:

toml
[source.aliases]
dep = { url = "https://dep.example", model = "https://dep.example/docmodel.json" }

Types reached through that alias link directly to their #anchor on the remote site. model accepts an http:// or https:// URL (cached per user with offline fallback) or a local path. Unreadable models emit a warning and fall back to module-level links.

The navbar ​

When [[site.nav]] isn't set, LuauDocs generates Guide, API, and Changelog links automatically (with activeMatch on Guide and API so they stay highlighted across subpages). Defining [[site.nav]] replaces the default navbar completely.

The guides sidebar ​

The /guide/ sidebar is built from page frontmatter and subdirectories:

yaml
---
title: Getting Started # or sidebar_label (falls back to the first heading)
sidebar_position: 1 # or order
description: One-line summary # optional (falls back to the first sentence of the page)
---

sidebar_position orders pages relative to siblings in the same folder. Unpositioned pages sort after positioned ones alphabetically by title, and index.md always leads its folder. llms.txt uses description as the page summary.

Folders and files starting with an underscore (_drafts/, _partial.md) are excluded from the sidebar, build output, search, and llms.txt.

When guide/ contains loose pages, everything sits under a top-level Guide heading. When guide/ contains only subfolders, each folder becomes its own top-level sidebar section.

Group settings ​

Configure a guide folder with a _category_.json (or .yml / .yaml) sidecar:

json
{
	"label": "API Reference",
	"position": 3,
	"collapsed": true
}
  • label: group title (defaults to the title-cased folder name).
  • position: order among sibling pages and folders (decimals such as 2.5 are supported).
  • collapsed: starts the group collapsed (default false).
  • collapsible: set to false to render a static header without a toggle.

A folder with an index.md can set sidebar_position, collapsed, and collapsible in index.md frontmatter instead. _category_ wins per key when both exist, and title in index.md names the page rather than the group. Invalid _category_ files fail the build.

Styling ​

init scaffolds .luaudocs/custom.css, which loads after the default stylesheet on every page so you can override brand colors, hero gradients, or VitePress theme variables. Delete the file to stop loading it.

The code font ​

Code blocks and inline code use bundled Fira Code with ligatures enabled (->, .., and <=, while Luau's ~= stays unligated). Customize it in custom.css:

css
/* keep the font, drop the ligatures */
.vp-doc code {
	font-variant-ligatures: none;
}

/* or use something else entirely */
:root {
	--vp-font-family-mono: "JetBrains Mono", monospace;
}

Guide-only sites ​

Set [source] entries = [] to skip the extractor and build only your landing page, guides, and changelog. This site points entries at examples/Flux so the guides can embed live API output.