mdoc

mdoc

  • Docs
  • Blog
  • GitHub

›Overview

Overview

  • Installation
  • Why mdoc?
  • Coming from tut
  • Changelog

Modifiers

  • JVM
  • Scala.js

Site generators

  • Docusaurus
Edit

Installation

Create a docs directory and docs/readme.md file with some basic content.

$ tree
.
└── docs
    └── readme.md
$ cat docs/readme.md
# My Project

To install my project
```scala
libraryDependencies += "com" % "lib" % "@VERSION@"
```

```scala mdoc
val x = 1
List(x, x)
```

We process the markdown with one of the following mdoc integrations:

  • sbt-mdoc: for usage with sbt projects.
  • command-line: to run from the console outside of a build tool.
  • library API: for programmatic usage.

The generated readme.md will look like this.

# My Project

To install my project

```scala
libraryDependencies += "com" % "lib" % "1.0.0"
```

```scala
val x = 1
// x: Int = 1
List(x, x)
// res0: List[Int] = List(1, 1)
```

Observe that VERSION has been replaced with 1.0.0 and that the scala mdoc code fence has been evaluated.

sbt

Install the sbt-mdoc plugin and create a docs project in build.sbt that enables mdoc.MdocPlugin.

Maven Central

// project/plugins.sbt
addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.7.1" )
// build.sbt
lazy val myproject = project  // your existing library
  .settings(...)
lazy val docs = project       // new documentation project
  .in(file("myproject-docs")) // important: it must not be docs/
  .dependsOn(myproject)
  .enablePlugins(MdocPlugin)

Next, from the sbt shell, run the docs/mdoc task to generate the documentation site. By default, the mdoc task looks for markdown sources in the toplevel docs/ directory.

// sbt shell
> docs/mdoc

Update mdocVariables to include site variables like @VERSION@.

// build.sbt
lazy val docs = project
  .in(file("myproject-docs"))
  .settings(
+   mdocVariables := Map(
+     "VERSION" -> version.value
+   )
  )
  .dependsOn(myproject)
  .enablePlugins(MdocPlugin)

The mdoc task runs the mdoc command-line interface so it's possible to pass in arguments like --watch to start file watcher with livereload. It's recommended to use --watch while writing documentation to enjoy 3-4x faster compilation performance.

> docs/mdoc --watch

See --help to learn more how to use the command-line interface.

> docs/mdoc --help

Reference

The sbt-mdoc plugin supports the following settings.

Task Type Description
mdoc InputTask[Unit] Run mdoc to generate markdown sources. Supports arguments like --watch to start the file watcher with livereload.
mdocIn File Input directory or source file containing markdown to be processed by mdoc. Defaults to the toplevel docs/ directory.
mdocOut File Output directory or output file name for mdoc generated markdown. Defaults to the target/mdoc directory of this project. If this is a file name, it assumes your `in` was also an individual file
mdocVariables Map[String, String] Site variables that can be referenced from markdown with @VERSION@.
mdocExtraArguments Seq[String] Additional command-line arguments to pass on every mdoc invocation. For example, add '--no-link-hygiene' to disable link hygiene.
mdocJS Option[Project] Optional Scala.js classpath and compiler options to use for the mdoc:js modifier. To use this setting, set the value to `mdocJS := Some(jsproject)` where `jsproject` must be a Scala.js project.
mdocJSLibraries Task[Seq[Attributed[File]]] Additional local JavaScript files to load before loading the mdoc compiled Scala.js bundle. If using scalajs-bundler, set this key to `webpack.in(<mdocJS project>, Compile, fullOptJS).value`.
mdocAutoDependency Boolean If false, do not add mdoc as a library dependency this project. Default value is true.

Command-line

Use coursier to launch mdoc outside of a build tool.

Maven Central

curl -L -o coursier https://git.io/coursier
chmod +x coursier
coursier launch org.scalameta:mdoc_2.12:2.7.1 -- --site.VERSION 1.0.0
info: Compiling 1 file to website/target/docs
info: Compiled in 1.2s (0 errors)

Add library dependencies to classpath

Use the --classpath argument to change the classpath used for compilation:

 coursier launch \
   org.scalameta:mdoc_2.12:2.7.1 -- \
+  --classpath $(coursier fetch -p org.typelevel:cats-core_2.12:1.5.0)

Customize input directory

By default the docs/ directory is processed as input. Use --in to customize the input directory where markdown sources are contained,

 coursier launch org.scalameta:mdoc_2.12:2.7.1 -- \
+  --in mydocs

Process single markdown file

The --in flag doesn't have to be a directory, it also supports individual files.

 coursier launch org.scalameta:mdoc_2.12:2.7.1 -- \
+  --in mydocs/readme.md

Configure site variables like @VERSION@

Use --site.VARIABLE=value to add site variables that can be referenced from markdown as @VARIABLE@.

 coursier launch org.scalameta:mdoc_2.12:2.7.1 -- \
+  --site.SCALA_VERSION 2.12.20

Customize output directory

Use --out to customize where your markdown sources are generated, by default the out/ directory is used.

 coursier launch org.scalameta:mdoc_2.12:2.7.1 -- \
+  --out target/docs

Generate single output file instead of directory

The --out flag doesn't have to be a directory when the --in argument is a regular file, it can also be an individual file.

 coursier launch org.scalameta:mdoc_2.12:2.7.1 -- \
+  --in readme.template.md \
+  --out readme.md

Process multiple input directories and files

Repeat the --in and --out arguments to process multiple directories and regular files.

 coursier launch org.scalameta:mdoc_2.12:2.7.1 -- \
+  --in readme.template.md \
+  --out readme.md \
+  --in changelog.template.md \
+  --out changelog.md \
+  --in mydocs-directory \
+  --out out-directory \

Live reload HTML preview on file save

Use --watch to start the file watcher with livereload. It's recommended to use --watch while writing documentation to enjoy 3-4x faster compilation performance.

 coursier launch org.scalameta:mdoc_2.12:2.7.1 -- \
+  --watch

Help

Use --help to learn more how to use the command-line interface.

mdoc v2.7.1
Usage:   mdoc [<option> ...]
Example: mdoc --in mydocs --out _site  (custom input/output directories)
         mdoc --watch                  (watch for file changes)
         mdoc --site.VERSION 1.0.0     (pass in site variables)
         mdoc --include **/example.md  (process only files named example.md)
         mdoc --exclude node_modules   (don't process node_modules directory)
         mdoc --in readme.template.md --out readme.md \
              --in examples.template.md --out examples.md (multiple input/output pairs)

mdoc is a documentation tool that interprets Scala code examples within markdown
code fences allowing you to compile and test documentation as part your build. 

Common options:

  --in | -i List[AbsolutePath] (default: ["docs"])
    The input directory or regular file containing markdown and other documentation
    sources that should be processed. Markdown files are processed by mdoc while
    non-markdown files are copied verbatim to the output directory. Can be
    repeated to process multiple input directories/files.

  --out | -o List[AbsolutePath] (default: ["out"])
    The output directory or regular file where you'd like to generate your markdown
    or other documentation sources. Must be repeated to match the number of
    `--in` arguments and must be a directory when the matching `--in` argument
    is a directory.

  --watch | -w
    Start a file watcher and incrementally re-generate the site on file save.

  --check
    Instead of generating a new site, report an error if generating the site would
    produce a diff against an existing site. Useful for asserting in CI that a
    site is up-to-date.

  --no-link-hygiene
    Disable link hygiene analysis so that no warnings are reported for dead links.

  --disable-using-directives
    Disable using directives syntax.

  --check-link-hygiene
    Link hygiene analysis reports dead links as errors. Useful for asserting in CI
    that the site contains no dead links. This setting has no effect in watch
    mode. It is also mutually exclusive with --no-link-hygiene, if both are set,
    link hygiene is disabled.

  --verbose
    Include additional diagnostics for debugging potential problems.

  --site Map[String, String] (default: {})
    Key/value pairs of variables to replace through @VAR@. For example, the flag
    '--site.VERSION 1.0.0' will replace appearances of '@VERSION@' in markdown
    files with the string 1.0.0

Compiler options:

  --classpath String (default: "")
    Classpath to use when compiling Scala code examples. Defaults to the current
    thread's classpath.You can use Coursier's fetch command to generate the
    classpath for you:`--classpath $(cs fetch --classpath
    org::artifact:version)`

  --scalac-options String (default: "")
    Space separated list of compiler flags such as '-Xplugin:kind-projector.jar
    -deprecation -Yrangepos'. Defaults to the value of 'scalacOptions' in the
    'mdoc.properties' resource file, if any. When using sbt-mdoc, update the
    `scalacOptions` sbt setting instead of passing --scalac-options to
    `mdocExtraArguments`.

  --clean-target
    Remove all files in the output directory before generating a new site.

LiveReload options:

  --no-livereload
    Don't start a LiveReload server under --watch mode.

  --port Int (default: 4000)
    Which port the LiveReload server should listen to. If the port is not free,
    another free port close to this number is used.

  --host String (default: "localhost")
    Which hostname the LiveReload server should listen to

Less common options:

  --help
    Print out a help message and exit

  --usage
    Print out usage instructions and exit

  --version
    Print out the version number and exit

  --markdown-extensions List[String] (default: ["md", "html"])
    Set of file extensions to treat as markdown files.

  --include List[PathMatcher] (default: [])
    Glob to filter which files to process. Defaults to all files. Example: --include
    **/example.md will process only files with the name example.md.

  --exclude List[PathMatcher] (default: [])
    Glob to filter which files from exclude from processing. Defaults to no files.
    Example: --include users/**.md --exclude **/example.md will process all
    files in the users/ directory excluding files named example.md.

  --report-relative-paths
    Use relative filenames when reporting error messages. Useful for producing
    consistent docs on a local machine and CI. 

  --charset Charset (default: "UTF-8")
    The encoding to use when reading and writing files.

  --cwd AbsolutePath (default: "<current working directory>")
    The working directory to use for making relative paths absolute.

  --allow-code-fence-indented
    Allow indented code fence blocks

  --import-map-path Option[AbsolutePath] (default: null)
    The absolute path to a file containing an import map file in this format;
    https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap

  --property-file-name String (default: "mdoc.properties")
    Defaults to mdoc.properties. This is the name of the properties file the CLI
    will read. It is assumed to be a resource on the classpath. Use the
    --extra-jars flag to customise the directory it is found in


Library

Add the following dependency to your build

Maven Central

// build.sbt
scalaVersion := "2.12.20" // Any version in 2.12.x works.
libraryDependencies += "org.scalameta" %% "mdoc" % "2.7.1"

Then write a main function that invokes mdoc as a library

It's recommended to use --watch while writing documentation to enjoy 3-4x faster compilation performance.

object Main {
  def main(args: Array[String]): Unit = {
    // build arguments for mdoc
    val settings = mdoc.MainSettings()
      .withSiteVariables(Map("VERSION" -> "1.0.0"))
      .withArgs(args.toList)
    // generate out/readme.md from working directory
    val exitCode = mdoc.Main.process(settings)
    // (optional) exit the main function with exit code 0 (success) or 1 (error)
    if (exitCode != 0) sys.exit(exitCode)
  }
}

If you use sbt-mdoc, update the mdoc task to call run instead of the default runMain mdoc.Main.

// build.sbt
lazy val docs = project
  .in(file("myproject-docs"))
  .settings(
+   mdoc := run.in(Compile).evaluated
  )
  .dependsOn(myproject)
  .enablePlugins(MdocPlugin)

Consult the mdoc source to learn more how to use the library API. Scaladocs are available here but beware there are limited docstrings for classes and methods. Keep in mind that code in the package mdoc.internal is subject to binary and source breaking changes between any release, including PATCH versions.

Why mdoc? →
  • sbt
    • Reference
  • Command-line
    • Add library dependencies to classpath
    • Customize input directory
    • Process single markdown file
    • Configure site variables like @VERSION@
    • Customize output directory
    • Generate single output file instead of directory
    • Process multiple input directories and files
    • Live reload HTML preview on file save
    • Help
  • Library
mdoc
Docs
Get started
Community
Chat on Gitter
More
GitHub
Copyright © 2025 mdoc developers