dotnet/Tooling
Docs as code with DocFX
basicsTL;DR
dotnet tool install -g docfx
docfx init -y # scaffold docfx_project/{docfx.json,toc.yml,index.md}
docfx build docfx_project/docfx.json --serve # build + preview at http://localhost:8080
<!-- csproj: emit the XML file DocFX reads for API reference -->
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
How it works
DocFX merges two content sources into one site. API reference is
extracted straight from your assemblies and their XML doc comments — a
Roslyn-based metadata step reads types, members, and <summary>/<param>
tags and turns them into structured reference pages, no writing required.
Conceptual docs are hand-written markdown for the things a member list
can’t explain: getting-started guides, architecture notes, tutorials.
docfx.json declares both halves. A metadata section points at the
.csproj/.dll files to extract API reference from; a build section
points at the markdown and toc.yml files to render as conceptual content,
plus the extracted API .yml the metadata step produced. Running
docfx build against a config with both sections runs the whole pipeline —
metadata extraction, then rendering — in one pass.
Navigation and cross-references
toc.yml files define the navigation tree, one per folder that needs its own
menu — a top-level one for the site’s main sections, nested ones for each
subsection’s own pages. DocFX assembles them into the sidebar you actually
browse.
Inside markdown, xref links (<xref:Namespace.Type.Member>, or the
@Namespace.Type.Member shorthand) resolve to API pages by symbol rather
than by URL. A conceptual doc that @-references a type survives that type
moving to a different namespace or file; a raw relative link to its generated
page does not.
Shipping it
The build output is static HTML — no server-side component, so it’s
deployable anywhere that serves files. A GitHub Pages workflow is close to
trivial: checkout the repo, install and run docfx build, then
actions/upload-pages-artifact on the generated _site folder followed by
actions/deploy-pages.
Gotchas
GenerateDocumentationFileturns on CS1591 for every public member. Once the compiler is generating the XML doc file, it also warns (CS1591: Missing XML comment for publicly visible type or member) for every public member that lacks one. Decide up front whether you’re documenting all publics or suppressing project-wide (<NoWarn>1591</NoWarn>) or per-member (#pragma warning disable CS1591) — don’t let hundreds of warnings pile up by accident.- Private and internal members are excluded by default. That’s intentional — DocFX’s metadata step only surfaces your public API surface unless you explicitly widen the filter. Resist the urge to expose internals just to document them.
- The default template is functional but generic. It renders correctly out of the box; making the site look like your docs rather than a docs site is where the actual customization effort goes.
- A docs build that only runs on your machine is already broken. Wire
docfx buildinto CI so brokenxrefs and stale API references fail the pipeline instead of shipping silently. - DocFX doesn’t version for you. Multi-version docs (v1 vs v2 API reference) mean running separate builds per version and arranging the output yourself — there’s no built-in version switcher.