CLI
|
This content was generated with the assistance of AI and should be verified against the official documentation of each tool before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
This page was written against DocFX 2.81.0 (the latest release, published on 2026-09-25) and checked on 2026-10-26. The
option lists below come from docfx --help and docfx <command> --help of the 2.81.0 tool, compared with the official
command-line reference and the 2.81.0 source. The commands were run with DocFX installed as a .NET tool in the
mcr.microsoft.com/dotnet/sdk:10.0 Docker image (SDK 10.0.403) against the Pocket Units C# library, so the listings show
real output. The tool and its commands are introduced in Basic Concepts and Pipeline;
this page is the reference for the command line itself.
The shape of the command line
DocFX ships as one executable, docfx, built on the Spectre.Console command-line library. Its general form is:
docfx [COMMAND] [config] [OPTIONS]
config is the path to a docfx.json file. When it is left out, DocFX reads docfx.json in the current folder; a path
that does not exist stops the command with Cannot find config file. Relative paths inside docfx.json are resolved
against the folder that holds the config file, not against the current folder. Parsing is strict: an unknown option makes
the command exit with code 255 without running anything (in the test run it also printed nothing).
docfx --version (or -v) prints the version followed by the commit hash (2.81.0 in this run).
docfx --help lists the commands and docfx <command> --help lists the options of one command.
| Command | What it does | Reads config sections |
|---|---|---|
|
Without a sub-command, runs the metadata, build and pdf stages in turn; accepts the build options |
|
|
Generates YAML files from .NET source code |
|
|
Generates the static site from the input files |
|
|
Generates PDF files from an already built site |
|
|
Hosts a folder on a local web server |
none |
|
Writes an initial |
none |
|
Lists the embedded templates ( |
none |
|
Downloads a remote xref map and saves it as a zip archive |
none |
|
Merges .NET API YAML files and TOC files |
|
default command"] DEF --> MD["metadata stage"] MD --> BLD["build stage"] BLD --> PDF["pdf stage"] PDF -.->|"--serve"| SRV["local web server"] CFG --> M["docfx metadata"] CFG --> B["docfx build"] CFG --> P["docfx pdf"] B -.->|"--serve"| SRV S["docfx serve folder"] --> SRV
How the commands relate. The bare docfx command runs the three stages in order, the dedicated commands run one stage
each, and --serve or docfx serve host the result.
Options shared by several commands
Four logging options are common to docfx, metadata, build, pdf and merge.
| Option | Meaning |
|---|---|
|
Writes the log as structured JSON, one object per line, to the given file |
|
Threshold: |
|
Shortcut for |
|
Counts warnings as errors, so the command exits with a failure code |
The log file holds one JSON object per line with severity, message, date_time and, for messages that belong to a
file, file, line and code. Running docfx build --logLevel warning -l build.log.json on a project whose index.md
links to a missing page produced one such line for the broken link:
{"severity":"warning","message":"Invalid file link:(~/guide/missing.md).","file":"index.md","line":"3","date_time":"2026-10-26T11:20:01.8017534Z","code":"InvalidFileLink"}
Besides the
command line, the rules section of docfx.json can change the severity of individual warning codes; see
docfx.json.
Exit codes
A command that logs at least one error ends with exit code 255 (the process shows -1). Warnings alone do not change the
code, which is why a broken link passes a build unless --warningsAsErrors is used. The same build, with one broken link
and each setting:
$ docfx build
/w/index.md(3,1): warning InvalidFileLink: Invalid file link:(~/guide/missing.md).
...
Build succeeded with warning.
1 warning(s)
0 error(s)
$ echo $?
0
$ docfx build --warningsAsErrors
/w/index.md(3,1): warning InvalidFileLink: Invalid file link:(~/guide/missing.md).
...
Build succeeded with warning.
1 warning(s)
0 error(s)
$ echo $?
255
The summary line still says "Build succeeded with warning" in the second run; the exit code is what a CI system sees.
Exceptions that DocFX does not handle itself, such as a missing config file or a missing Node.js installation, are
printed as an error: FatalError: line followed by the exception and a stack trace and also end with 255. The commands serve, template and
download do not print the build summary and return 0 when they finish normally.
The bare docfx command
docfx with no sub-command is the everyday entry point. As the source shows, it loads the config and then:
-
runs the metadata stage when the config has a
metadatasection; -
runs the build stage when the config has a
buildsection, applying the build options below; -
runs the pdf stage, which only produces files for tables of contents that opt in with
pdf: true; -
hosts the output when
--servewas given.
So the three forms below differ in what they run. docfx docfx.json and docfx are the same when the file is named
docfx.json.
docfx # metadata, build and pdf with ./docfx.json
docfx docfx.json --serve # the same, then host _site at http://localhost:8080
docfx build docfx.json # build stage only: api/*.yml must already exist
Source: DocFX docs: docfx
The last form is the one that surprises people: docfx build does not run metadata and does not run pdf. With a
fresh checkout where the generated api folder is not committed, docfx build warns that it cannot find toc.yml in
api/ and the API section is empty. The bare command, or docfx metadata followed by docfx build, avoids that.
docfx metadata
docfx metadata [config] extracts YAML from C# and Visual Basic projects, solutions, assemblies and source files (the
inputs and keys are described in .NET API docs). Besides the shared
logging options it accepts the following. They override the same-named keys of the metadata section of docfx.json
for every entry of that section.
| Option | Meaning (from docfx metadata --help) |
|---|---|
|
Output base directory |
|
Output type ( |
|
Filter config file (the |
|
Name to use for the global namespace |
|
MSBuild properties used when reading project files, written |
|
Do not fetch Git information; no View Source links are generated |
|
Do not apply the default filter, which keeps only public or protected APIs |
|
Do not run |
|
Category layout in the generated table of contents |
|
Namespace layout in the generated table of contents ( |
|
Member page layout ( |
|
Skip converting the triple-slash comments to Markdown |
Source: DocFX docs: docfx metadata
The help text gives the meaning of each option but not the accepted values of --outputFormat and the layouts; the
values in the table are the ones of the matching docfx.json keys. Running it on Pocket Units:
docfx metadata
Loading project /w/src/PocketUnits/PocketUnits.csproj
Determining projects to restore...
Restored /w/src/PocketUnits/PocketUnits.csproj (in 789 ms).
Processing PocketUnits
Creating output...
Build succeeded.
0 warning(s)
0 error(s)
The api folder then holds PocketUnits.yml, PocketUnits.Converter.yml, PocketUnits.LengthUnit.yml and a generated
toc.yml.
docfx build
docfx build [config] renders the site. The options fall into groups.
Output, templates and metadata
| Option | Meaning |
|---|---|
|
Output base directory. It replaces the |
|
Template name(s) to apply, replacing the |
|
Theme to use; the help states that |
|
A global metadata key and value, |
|
URL or path of an xref map used by the content; added to the |
|
The order of the post processors, replacing the config value |
|
Markdig settings as a JSON string, replacing |
|
Maximum parallelism; 0 lets DocFX decide |
|
Do not fetch Git information for the articles. The default is on, and on a large repository it can slow the build |
Running docfx build -o out1 -m _appTitle="Pocket Units" -m _disableContribution -t default,modern wrote the site to
out1 and the page title became "Pocket Units | Pocket Units", showing that the metadata value reached the template. The
site-wide _appTitle and the other underscore keys are explained in
Templates and customization.
Serving the result
| Option | Meaning |
|---|---|
|
Host the generated site after the build |
|
Host name of the server, for example |
|
Port of the server; the default is 8080 |
|
Open the default browser when the server starts |
|
Open a specific file of the site instead of the home page |
With --serve the command keeps running until it is stopped with Ctrl+C. Before building, DocFX checks whether the port
is already taken. When it is, the build is not started:
$ docfx build --serve -p 8099
error: Serve option specified. But TCP port 8099 is already being in use.
Build failed.
0 warning(s)
1 error(s)
This ended with exit code 255. The same check runs for the bare docfx --serve. With --hostname '*' any listener on the
port counts as a conflict, and a host name that is not a valid IP address is treated the same way. A normal run prints:
Serving "/w/_site" on http://localhost:8101
Press Ctrl+C to shut down
Debugging the templates
These options are for people who write templates or investigate a rendering problem; they are not needed for ordinary builds.
| Option | Meaning |
|---|---|
|
Do not apply the templates. The documents are processed (links, xrefs, models) but no HTML is written |
|
Write the data model that is passed to the template script, as |
|
Folder for the raw model; by default the output folder |
|
Write the model after the template script ran, as |
|
Folder for the view model; by default the output folder |
|
Debug mode: the raw and view models are exported automatically when applying a template fails |
|
Folder for the debug files; by default a |
The help text names the extensions .raw.model.json and .view.model.json; the files written in the test run were
named index.raw.json and toc.raw.json. The help also says that --dryRun is always used together with
--exportRawModel or --exportViewModel; the flag can also be given on its own, as in the first run below.
docfx build --dryRun
docfx build --dryRun --exportRawModel --rawModelOutputFolder raw
Dryrun, no template will be applied to the documents.
Building 1 file(s) in ConceptualDocumentProcessor(BuildConceptualDocument=>ValidateConceptualDocumentMetadata)...
Building 3 file(s) in ManagedReferenceDocumentProcessor(...)...
Building 2 file(s) in TocDocumentProcessor(BuildTocDocument)...
Applying templates to 6 model(s)...
XRef map exported.
Build succeeded.
After the first command the _site folder contained only manifest.json and xrefmap.yml: no HTML, no public
folder. After the second, raw contained index.raw.json, toc.raw.json and an api folder with one raw file for each
generated page. A dry run is therefore a quick way to validate links and cross-references (warnings still appear) and to
see the model a custom template would receive; the exported xrefmap.yml also lists every UID. The model formats are
described with the templates in Templates and customization.
Source: DocFX docs: docfx build
docfx pdf
docfx pdf [config] accepts only the logging options and -o, --output (output base directory). It does not build the
site: it reads manifest.json in the output folder and renders the pages of every table of contents that carries
pdf: true in its metadata, using a headless Chromium driven by Playwright. The stage therefore needs a finished
docfx build. Two failures seen in the test image:
$ docfx pdf # before any build
Searching for manifest in /w/_site
error: FatalError: System.IO.DirectoryNotFoundException: Could not find a part of the path '/w/_site/manifest.json'.
$ docfx pdf # after a build, with "pdf": true in globalMetadata
Searching for manifest in /w/_site
error: FatalError: Docfx.Exceptions.DocfxException: Node.js executable is not found. Try to install Node.js or set the `PLAYWRIGHT_NODEJS_PATH` environment variable.
Both ended with exit code 255. Without pdf: true anywhere, the command finds the manifest, has nothing to render and
finishes with "Build succeeded". The Node.js message shows how DocFX works: it looks for a node executable on PATH
and sets PLAYWRIGHT_NODEJS_PATH for itself, unless PLAYWRIGHT_NODEJS_PATH or PLAYWRIGHT_DRIVER_SEARCH_PATH is
already set. A successful PDF run needs Node.js and the Playwright browsers, which this image lacks; the run that
produced PDFs is described on the PDF output page, which also explains the PDF metadata keys and the template requirement are explained in
PDF output. Because the bare docfx command runs the pdf stage, a CI job
that runs docfx on a config with pdf: true needs Node.js too, while docfx build does not.
Source: DocFX docs: docfx pdf
docfx serve
docfx serve [directory] hosts a folder of static files and does nothing else; it never builds. The folder defaults to
the current directory. Options: -n, --hostname, -p, --port, --open-browser and --open-file <RELATIVE_PATH>,
with the same meaning and defaults (localhost, 8080) as for build --serve.
docfx serve _site -p 8099
Serving "/w/_site" on http://localhost:8099
Press Ctrl+C to shut down
A request for / and for /index (no extension) both returned 200; the server maps extension-less URLs to .html
files, which makes a local preview behave like hosts that use clean URLs. A folder that does not exist ends with
Site folder does not exist. You may need to build it first. and an exception trace. The server is meant for a local
preview only: it listens on plain HTTP and has no access control. The official example shows docfx --serve _site
for the second case, which is a typographical slip in the reference; the working command is docfx serve _site.
Source: DocFX docs: docfx serve
docfx init
docfx init is a short wizard that writes a starter project. Options: -y, --yes (accept all defaults, ask nothing)
and -o, --output (folder to write into, default the current folder). The questions are the project name (default
mysite), whether to generate .NET API documentation, where the .NET projects are (default src), where the Markdown
documents go (default docs), whether to enable site search and whether to enable PDF. Before writing docfx.json
it shows the content and asks for confirmation; declining ends the command with "Aborted." and exit code 255. An existing
file is only replaced after the same confirmation.
docfx init -y -o /w/newsite
This utility will walk you through creating a docfx project.
It only covers the most common items, and tries to guess sensible defaults.
Project created at /w/newsite
Run docfx /w/newsite/docfx.json --serve to launch the site.
It created docfx.json, toc.yml, index.md, docs/introduction.md, docs/getting-started.md and docs/toc.yml.
The generated docfx.json is worth reading, because it shows the idiomatic minimal configuration:
{
"$schema": "https://raw.githubusercontent.com/dotnet/docfx/main/schemas/docfx.schema.json",
"metadata": [
{ "src": [ { "src": "../src", "files": [ "**/*.csproj" ] } ], "dest": "api" }
],
"build": {
"content": [ { "files": [ "**/*.{md,yml}" ], "exclude": [ "_site/**" ] } ],
"resource": [ { "files": [ "images/**" ] } ],
"output": "_site",
"template": [ "default", "modern" ],
"globalMetadata": { "_appName": "", "_appTitle": "", "_enableSearch": true, "pdf": true }
}
}
The listing is the generated file with the indentation compacted. Note that the .NET projects are expected one folder
above the config file (../src), so run the wizard inside a docs folder next to src, as the
overview does, or edit the path. With -y the name is empty, search and PDF
are on, and pdf: true in globalMetadata means the bare docfx command will try to build PDFs, so Node.js has to be
available there. The $schema line gives editors completion for docfx.json.
Source: DocFX docs: docfx init
docfx template
docfx template list prints the templates embedded in the installation, one per line. docfx template export [template]
copies the files of a template so they can be inspected or used as a starting point. Options of export: -a, --all
(export every template) and -o, --output (target folder; the default is _exported_templates). With no template
name, all templates are exported.
docfx template list
docfx template export modern -o /w/tpl
docfx template export nope
modern
default(zh-cn)
common
statictoc
default
modern is exported to /w/tpl
warning: No resource found for [nope].
warning: Cannot find template nope.
Each template is written to a subfolder named after it (/w/tpl/modern); for modern the export contains
ApiPage.html.primary.js and a public folder with the bundled scripts and styles (Mermaid, KaTeX, Lunr and others).
An unknown name is only a warning. Exporting is the starting point for the customisation described in
Templates and customization.
Source: DocFX docs: docfx template
docfx download
docfx download <path> --xref <url> downloads a remote xref map (a .json or .yml file) and stores it as a zip
archive at path. The archive is a zip whatever extension the path has, and its content is converted to
xrefmap.yml. The official example downloads the map that DocFX publishes for its own site. The test used a map served
from the local site, which keeps the example runnable offline:
docfx serve _site -p 8200 &
docfx download xr.zip --xref http://localhost:8200/xrefmap.yml
/w/xr.zip: Creating xref archive file...
/w/xr.zip: Xref archive file created.
The archive held one file, xrefmap.yml (2593 bytes), starting with ### YamlMime:XRefMap, sorted: true,
baseUrl: http://localhost:8200/ and the references of the Pocket Units API. The base URL recorded in the archive is
where the links of the other site point. An xref archive cannot itself be a download source: DocFX warns that
downloading an archive, or referencing one, is not supported. How to consume an xref map from build.xref is explained
in Links and cross-references.
Source: DocFX docs: docfx download
docfx merge
docfx merge [config] is meant to merge the API YAML files and TOC files of several target frameworks into one set. It
reads the merge array of docfx.json (each entry has content, dest, globalMetadata, fileMetadata and
tocMetadata) and accepts the logging options and -o, --output. The official page carries a warning that the
command is broken and does not work as expected, with a link to an issue in the DocFX repository. That matches what was
seen in 2.81.0: with no merge section the command ends with a NullReferenceException, and with a minimal valid
section it also ends with a NullReferenceException while loading the models:
{ "merge": [ { "content": [ { "files": ["api/*.yml"], "exclude": ["api/toc.yml"] } ], "dest": "merged" } ] }
$ docfx merge merge.json
Start merge metadata...
error: System.NullReferenceException: Object reference not set to an instance of an object.
at Docfx.Build.Engine.HostServiceCreator.LoadModels(...)
The exit code was 255 and no merged folder was written. Do not build a pipeline on docfx merge. For multi-targeted
libraries, choose one target framework with the properties key (see
.NET API docs).
Source: DocFX docs: docfx merge
Environment variables
DocFX reads a few environment variables. Five are documented in the official reference; the sixth, a Playwright variable, appears in the source and in the error message above.
| Variable | Effect |
|---|---|
|
Overrides the Git branch name used for View Source and Improve this Doc links |
|
Overrides the organisation and repository, in the form |
|
When true, keeps source-tracking attributes ( |
|
Disables the certificate revocation check; intended for offline environments |
|
Playwright default timeout, in milliseconds, for PDF generation |
|
Node.js executable used by |
DOCFX_SOURCE_BRANCH_NAME and DOCFX_SOURCE_REPOSITORY_URL are useful in CI, where a checkout is often a detached HEAD
or a fork. Both are read when the Git information is computed, which is in the metadata stage for API pages, so the
variable has to be present when docfx metadata (or the bare docfx) runs, not only at build. In the test the project
was a Git repository on branch feature-x with the remote https://github.com/example/pocket-units.git. The View
Source link of Converter.cs was:
https://github.com/example/pocket-units/blob/feature-x/src/PocketUnits/Converter.cs/#L12
and after running DOCFX_SOURCE_BRANCH_NAME=docs-main DOCFX_SOURCE_REPOSITORY_URL=https://github.com/other/fork docfx metadata
followed by docfx build:
https://github.com/other/fork/blob/docs-main/src/PocketUnits/Converter.cs/#L12
The generated YAML records the values under source, as branch: docs-main and repo: https://github.com/other/fork.
Setting the variables only for the build command left the links unchanged. DOCFX_KEEP_DEBUG_INFO was not exercised:
the test pages contained none of the listed attributes with or without it, so its effect is taken from the reference.
DOCFX_PDF_TIMEOUT and the Node.js variable belong to the PDF stage that was not executed.
Running DocFX from code with Docfx.App
DocFX is also published as the NuGet package Docfx.App ("Docfx published as a library for extensibility and advanced
customization" in its description). It exposes a static Docset class with Build(string configPath) and
Pdf(string configPath) (each with an overload that takes a BuildOptions value) and, in the namespace Docfx.Dotnet,
DotnetApiCatalog.GenerateManagedReferenceYamlFiles(string configPath), which is the metadata stage. BuildOptions has
one property, ConfigureMarkdig, a delegate that receives the Markdig MarkdownPipelineBuilder, so a program can add
Markdown extensions. DotnetApiOptions can filter symbols with callbacks; it is covered in
.NET API docs. The official page warns that the versions of the
Microsoft.CodeAnalysis.* packages must match what Docfx.App was built against.
The following console program is the equivalent of docfx metadata followed by docfx build. It was built and run
with the .NET 10 SDK against Pocket Units:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Docfx.App" Version="2.81.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="5.9.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="5.9.0" />
</ItemGroup>
</Project>
using Docfx;
using Docfx.Dotnet;
// Equivalent of `docfx metadata` followed by `docfx build`.
await DotnetApiCatalog.GenerateManagedReferenceYamlFiles("docfx.json");
await Docset.Build("docfx.json");
The two Roslyn packages are pinned to 5.9.0 because that is the version the 2.81.0 source uses for its net10.0 target
(it uses a different one for net8.0 and net9.0). Without them, the program built but failed at run time with
The build host could not be found at '.../BuildHost-netcore/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.dll'.
Started from the folder that holds docfx.json, it printed the same messages as the command line (Loading project,
Processing PocketUnits, Applying templates to 6 model(s), Build succeeded.) and produced the api and _site
folders. Note that the program printed Searching built-in plugins in directory .../bin/Debug/net10.0/: the plug-ins
and templates are taken from the application’s own output folder.
A complete Pocket Units session
A typical CI sequence, assuming the project layout of the overview page:
dotnet tool install -g docfx --version 2.81.0
export PATH="$PATH:$HOME/.dotnet/tools"
docfx metadata docfx.json --logLevel warning -l metadata.log.json
docfx build docfx.json --warningsAsErrors --logLevel warning -l build.log.json
docfx serve _site --port 8080
The two logs are structured JSON, so a later step can filter by severity. The deployment of the result is the topic of
Deployment.
Pitfalls and version notes
-
docfx buildalone never regenerates the API YAML and never creates PDFs; use the baredocfxcommand or run the stages in order. -
Warnings do not fail a build. Use
--warningsAsErrors; the exit code is 255, although the console still says "Build succeeded with warning". -
--serverefuses to start when the port is taken, before building anything. -
--dryRunwritesmanifest.jsonandxrefmap.ymlbut no HTML. -
The bare
docfxcommand runs the pdf stage; withpdf: truein the metadata it needs Node.js onPATH(orPLAYWRIGHT_NODEJS_PATH) and the Playwright browsers. -
Set
DOCFX_SOURCE_BRANCH_NAMEandDOCFX_SOURCE_REPOSITORY_URLfor the metadata stage, not only for build. -
docfx mergeis documented as broken and failed in 2.81.0. -
docfx initwrites../srcas the projects folder; run it where that path is right. -
Release 2.80.1 made metadata generation stop when
dotnet restorefails; run it with--noRestoreonly when the projects were restored before. -
DocFX has no fixed release schedule and is maintained by the community under the .NET Foundation; check
docfx --helpafter an upgrade, because options are not versioned in the reference pages.