~/handys11
Browse the docs

dotnet/Tooling

Docs as code with DocFX

basics

TL;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.

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

  • GenerateDocumentationFile turns 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 build into CI so broken xrefs 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.

Further reading