WritedocsWritedocs

CLI Reference

Writedocs is meant to be installed globally (npm install -g writedocs, see Quickstart) — install it once, then run writedocs directly from inside any project’s own folder. No local package.json dependency, no per-project install step.

Every command takes an optional [dir] argument — the content directory containing writedocs.json and docs/. It defaults to the current directory, so you can cd into your docs project and run these with no arguments, or point them at a project elsewhere without cd-ing first:

writedocs dev              # serves the current directory
writedocs dev ./my-docs    # serves ./my-docs instead

Skipped the global install? Every command here also works prefixed with npx instead — npx writedocs dev — which downloads and runs Writedocs on the fly.

There’s no writedocs build here — building the static site and deploying it isn’t a step you run yourself. dev, validate, broken-links, a11y, init, and update cover everything you need day to day.

writedocs dev

Starts a local preview of your site and opens it in your browser. Edit any page and the preview updates.

writedocs dev [dir]
✓ Preview ready in 3.9s

  Local:  http://localhost:4321/

  Edit any page and the preview updates. Press Ctrl+C to stop.

While it runs, it tells you about problems as you hit them, with the file and line:

✗ docs/guides/setup.mdx:24:1  Expected a closing tag for `<Card>`
⚠ docs/guides/setup.mdx:14  Unknown component <CustomBanner> - showing only its content. Remove it, or define it in a snippet.
⚠ /docs/guides/old-page/  No page at this address (404).
FlagDescription
-p, --port <port>Port to run the preview on. Default: 4321. If it’s in use, the next free port is used, and the output says so.
--verboseAlso print the output of the tools writedocs runs underneath. Useful when reporting a bug.
--no-openDon’t open the preview in the browser. It also stays closed with BROWSER=none set, in CI, and when the output isn’t a terminal.
writedocs dev --port 3000

One preview runs at a time. Starting a second one - even for a different project - stops with a message saying where the first is running; stop it with Ctrl+C first.

writedocs validate

Checks writedocs.json and every page, and lists every problem it finds in one run - before a build would stop at the first one.

writedocs validate [dir]

Errors - the build would fail. validate exits with code 1:

  • writedocs.json doesn’t match its schema, or isn’t valid JSON.
  • A page’s frontmatter isn’t valid YAML, or doesn’t match what a page accepts (for example, a missing title or an unknown mode).
  • A .mdx page has an MDX syntax error, like an unclosed component.
  • A Markdown image with a relative path (![Diagram](./diagram.png)) names a file that doesn’t exist.
  • The navigation lists a page that doesn’t exist.
  • A redirect uses a pattern (/old/:slug, /old/*) - writedocs redirects match one exact path.
  • An OpenAPI group’s spec (openapi.src) doesn’t exist, is a URL instead of a file in the project, or doesn’t parse - or two OpenAPI groups use the same openapi.path.

Warnings - the site still builds, but not exactly as written. validate exits with code 0:

  • A component writedocs doesn’t have, like a custom component from another docs tool. The build shows only the content inside it.
  • An icon name that isn’t in any installed icon set - in a component’s icon, a page’s icon, or writedocs.json. The build leaves it out.
  • A built-in component inside a page component that runs as React (one that uses React hooks, or is passed to a React snippet). It renders simplified there - see Snippets.
  • An unknown top-level key in writedocs.json.
  • A page’s openapi frontmatter names an operation no spec has (GET /pet instead of GET /pets), or a spec that doesn’t exist or doesn’t parse. The page shows a notice instead of the API playground.
  • An OpenAPI spec that parses but isn’t valid OpenAPI. The build uses it as it is, so its API pages may be incomplete.

Each problem names the file and line, and what to do about it:

⚠ 1 warning in the pages

  docs/guides/setup.mdx:14
    Unknown component <CustomBanner> - the build shows only its content.
    Remove it, use a writedocs component instead, or define it in a snippet.
FlagDescription
--config-onlyCheck writedocs.json only, not the pages.

Because the exit code is 1 only for errors, writedocs validate works as a CI step: it fails on anything that would break the build, and reports the rest.

Checks every link in your pages and writedocs.json against the site the build would produce, without building it.

writedocs broken-links [dir]

A link is broken when:

  • There’s no page at its address - including a page that moved because of a frontmatter slug, or a typo.
  • Its #anchor isn’t on the target page. Anchors are headings, the titles of callouts, accordions and updates, and elements with an id.
  • It links to a file that isn’t published. Files in public/ are published; an image elsewhere in the project is published only where a page displays it, not for a plain link to it.
  • It links to a page’s source file (./setup.mdx) instead of its URL.

Relative links resolve the way a browser resolves them, from the page’s URL. Page URLs end in a slash (/docs/guides/setup/), so [Install](install) on that page points to /docs/guides/setup/install/ - the output says so, and what to write instead.

✗ 2 broken links

  docs/guides/setup.mdx:12
    install - relative links resolve from the page's own URL (/docs/guides/setup/), so this one points to /docs/guides/setup/install/, which doesn't exist.
    Write /docs/guides/install/ instead.

  docs/guides/setup.mdx:30
    #configuraton - this page has no heading or anchor "#configuraton".
    Did you mean #configuration?

✗ 2 broken links - checked 214 links in 31 pages (12 external links not checked)

Links to other sites (https://, mailto:) aren’t checked. The command exits with code 1 when it finds a broken link, so it works as a CI step next to writedocs validate.

writedocs a11y

Checks for accessibility problems you can fix in your pages and writedocs.json.

writedocs a11y [dir]
  • Color contrast of the colors writedocs.json sets, against WCAG AA (4.5:1 for text): links (styles.colors.primary) on the light and dark backgrounds, body text (styles.colors.text), white text on the primary color (step numbers, the info banner), and the navbar’s text on styles.navbar. Dark mode uses the same primary color unless you set styles.colors.dark.primary - a dark blue that works on white often doesn’t on the dark background.
  • Images without alt text - ![](/diagram.png), or an <img> or <Image> with no alt. For a purely decorative image, write alt="".
  • An <iframe> without a title.
  • A link with no text, which a screen reader reads out as its address.
  • Headings that skip a level - the page title is the page’s h1, so sections start at ##, and ## followed by #### skips one. A # heading in the page is a second h1. Pages with mode: custom or mode: blank have no title heading, so their own # heading is expected.
✗ 2 accessibility issues

  writedocs.json:10
    Links are hard to read in dark mode: the primary color #0029F5 on the dark background #0b1120 has a contrast of 2.36:1 (needs 4.5:1).
    Set a lighter styles.colors.dark.primary for dark mode.

  docs/guides/setup.mdx:18
    Heading level skips from h2 to h4 ("Options").
    Use ### here, or add the missing level above it.

✗ 2 accessibility issues - checked writedocs.json and 31 pages

Like broken-links, it exits with code 1 when it finds something, so it can run in CI.

writedocs convert

Converts another docs tool’s configuration into writedocs.json - a Mintlify project, or a project from the previous writedocs:

writedocs convert --mintlify [dir]
writedocs convert --writedocs [dir]

With --mintlify, it reads docs.json from the project folder (following any $ref files it points to); with --writedocs, config.json. It writes writedocs.json next to it. Your pages stay where they are.

Then it prints two lists:

  • What couldn’t be carried over as-is, with the field each item came from - settings writedocs doesn’t have, navigation that had to change shape (anchors become tabs, for example), and anything you need to do by hand, like downloading an OpenAPI spec that was a URL.
  • What writedocs validate finds in your pages with the new writedocs.json - errors to fix before the first build, and warnings.
FlagDescription
--mintlifyConvert a Mintlify project’s docs.json. --docs.json does the same.
--writedocsConvert the previous writedocs’ config.json. --config.json does the same.
--forceOverwrite an existing writedocs.json. Without it, convert stops rather than replace one.
--dry-runPrint the converted writedocs.json and both lists, without writing anything.

An older Mintlify project with mint.json instead of docs.json needs npx mint upgrade first. See Migrating from Mintlify and Migrating from the previous writedocs for the full picture.

writedocs init

Scaffolds writedocs.json and a starter docs/ folder.

writedocs init [dir]

Creates:

  • writedocs.json — a minimal config with one navigation group.
  • index.mdx — a welcome page, at the project root.
  • docs/getting-started.mdx — a short getting-started guide.

Existing files are never overwritten — init skips (and prints a message for) any file that already exists, so it’s safe to run again in a project you’ve already started customizing.

writedocs update

Updates writedocs to the latest version.

writedocs update

It updates writedocs the way you installed it: a global install with npm install -g, or - when writedocs is a dependency of your project - in that project, with npm, pnpm or yarn (whichever lockfile the project has). If you run writedocs through npx, it tells you how to run the latest version instead.

When a newer version is out, every command says so after its output:

ℹ writedocs 0.8.0 is available (you have 0.7.1). Run writedocs update to update.

The check never slows a command down: writedocs asks npm at most once a day, in the background, and shows the answer on the next run. It’s off in CI and when the output isn’t a terminal. To turn it off, set the environment variable WRITEDOCS_NO_UPDATE_CHECK=1.