rguides

Documenting with roxygen2

Every R package that appears on CRAN ships with .Rd documentation files in its man/ directory. These are the files R fetches when a user calls ?mean or help("subset"). Before roxygen2 existed, you had to write those .Rd files by hand using a cryptic markup syntax. That was error-prone and annoying. roxygen2 changed that by letting you write documentation in regular R comments, then generating the .Rd files automatically.

The idea is simple: put special #' comment blocks above your functions in the R/ directory, run devtools::document(), and out come properly formatted .Rd files. Your source code and documentation live side by side, which makes maintenance easier. This is now the standard approach for documenting R package functions.

How roxygen blocks work

A roxygen block is a sequence of lines that start with #'. Place one directly above a function definition in any file under R/:

#' Sum of vector elements
#'
#' `sum` returns the sum of all the values present in its arguments.
#'
#' @param ... Numeric values to sum.
#' @param na.rm Logical. If TRUE, NA values are removed.
#' @return A single numeric value.
#' @examples
#' sum(c(1, 2, 3))
#' sum(c(1, NA), na.rm = TRUE)
#' @export
sum <- function(..., na.rm = FALSE) {
  sum(c(...), na.rm = na.rm)
}

The block sits above the function. Roxygen2 reads every #' line in your R/ directory, parses the content, and writes a corresponding .Rd file to man/. It also updates NAMESPACE based on @export and @importFrom tags.

A block has two parts. The free-form text before the first @ tag forms the introduction. The first line is the title (one sentence, sentence case, no period). The second paragraph is the description. Any paragraphs after that form the details section. Then the @ tags describe specific components like parameters, return values, and examples.

The essential tags

@param, @return, @examples, and @export are the tags you will reach for on every function.

Documenting parameters

Use @param to describe each argument. The format is @param name type description, type is optional but recommended:

#' @param x A numeric vector.
#' @param trim Real number between 0 and 0.5. Amount to trim from each tail.

If multiple parameters share a description, list them separated by commas: @param x,y Numeric vectors.

The description should tell users what the parameter does, not just its type. “A numeric vector” is less useful than “A numeric vector of values to summarise.”

Describing return values

@return documents what the function gives back. Keep it brief, state the type and shape, not the implementation:

#' @return A numeric vector of length one.

For functions that return different types depending on input, describe the common case and note variations in details.

Writing examples

Examples are the most valuable part of documentation, but they must run without error. R CMD check executes them automatically, so broken examples fail the check.

#' @examples
#' mean(c(1, 2, 3))
#' mean(c(1, NA), na.rm = TRUE)

If an example should error under normal use, wrap it in try() or \dontrun{}:

#' @examples
#' \dontrun{
#' read_csv("nonexistent.csv")
#' }

For examples that should only run in an interactive session (like ones requiring user input), use @examplesIf interactive() instead.

Making functions available with @export

Without @export, a function is invisible to package users, it exists in the code but cannot be accessed via library(mypackage). Adding @export above a function does two things: it generates an export() directive in NAMESPACE, and it causes roxygen2 to create a user-facing help page for that function.

#' @export
my_function <- function(x) {
  x + 1
}

Internal helper functions that users should not call directly can omit @export. You can suppress the .Rd file entirely with @noRd if you want to keep the roxygen comments for developer reference without creating a help page.

Importing from other packages

Use @importFrom to pull in specific functions from other packages without loading the whole package with library(). This goes in the roxygen block of whichever function uses the imported function, or at the package level (above NULL or in a dedicated file like R/utils.R):

#' @importFrom magrittr %>%
#' @importFrom rlang .data
NULL

Running devtools::document() adds the corresponding importFrom() directives to NAMESPACE and updates the Imports: field in DESCRIPTION automatically.

Markdown in roxygen2

Since roxygen2 version 6.0, Markdown is supported. Enable it globally by adding to your DESCRIPTION:

Roxygen: list(markdown = TRUE)

Or enable it per-block with the @md tag at the start of a block. Markdown lets you use backticks for inline code, fenced code blocks, bold, italics, and hyperlinks:

#' @md
#' The `mean()` function supports [trimmed means][base::mean].

If you enabled Markdown globally but need to disable it for a specific block, use @noMd.

Generating documentation

Once your roxygen blocks are in place, generate the .Rd files by running:

devtools::document()

This is the equivalent of calling roxygen2::roxygenise(). The function reads every #' block in R/, parses all tags, writes .Rd files to man/, and updates NAMESPACE. You will run this command hundreds of times while developing a package, it is idempotent, so running it again does no harm.

You generally never edit the generated .Rd files by hand. They get overwritten every time you call document(). If you need to add content that roxygen2 cannot express, edit the roxygen source block and re-run document().

The @seealso tag adds a “See Also” section to the generated help page, linking to other topics:

#' @seealso [mean()] for the generic, [var()] for variance.

Use @family to group related functions together. Every function tagged with @family utility appears in every other function’s auto-generated “See Also” section:

#' @family utility functions

This is useful for a set of helper functions that serve related purposes.

Common patterns

Inheriting parameter documentation

If your function wraps another and accepts the same parameters, use @inheritParams to copy the documentation:

#' @inheritParams base::merge

This avoids repeating the same descriptions and keeps documentation consistent across a package.

Documenting multiple functions together

Use @describeIn and @rdname to share documentation across multiple functions or to document method-specific behavior in a single block:

#' @param x Numeric vector.
#' @describeIn my_generic
#' Description of the specific method behavior.
my_method <- function(x) { ... }

This puts both the generic and the method in the same .Rd file under different sections.

What gets generated

When you run devtools::document(), the tool produces a .Rd file for every exported function that has a roxygen block. The file lives in man/ and follows the standard R documentation format. It also produces NAMESPACE entries from @export and @importFrom tags, and updates DESCRIPTION fields like Imports: and RoxygenNote.

If you are submitting to CRAN, the documentation must pass R CMD check without warnings. That means every exported function needs a title, a description, @param for every argument, and @return. Examples must run cleanly. Getting this right with roxygen2 is straightforward, the tags map directly to the requirements.

Documentation as the package’s public face

Documentation is what distinguishes a polished package from a collection of functions. Users judge package quality partly by documentation quality. Missing documentation for exported functions fails R CMD check. Unclear documentation produces support requests. Good documentation reduces the time from “found this package” to “using this package productively.”

roxygen2 puts documentation in the code file, adjacent to the function it documents. This proximity makes documentation easier to keep current, when you change a function, the documentation is in the same file, immediately visible. Documentation written in a separate file falls out of sync as the code evolves. The inline approach is standard in modern R package development.

What each tag documents

The @param tag documents one function parameter. Include the expected type and what the function does with it. For parameters with non-obvious defaults, explain what the default means. For parameters that accept special values like NULL or Inf, explain their behavior separately. Writing one @param per parameter, rather than combining multiple parameters in one @param, enables hyperlinking to individual parameter documentation.

The @return tag documents the return value: its type, its structure, and any conditions under which the return value differs (NULL instead of a data frame when no results are found, a list with different components for different input types). Users reading the @return section decide whether to use the function for their purpose. An unhelpful “Returns the result” fails this purpose; a complete description of what the return value contains serves it.

The @examples section shows the function in use. Examples are executable, R CMD check runs them, and users run them interactively with example(). Write examples that demonstrate the function’s primary use and at least one interesting variation. Keep examples fast: they run in the check environment where slow examples time out. For examples that require network access or large data, wrap them in \dontrun{} or \donttest{}.

Cross-Referencing and linking

The @seealso and @family tags create relationships between related functions. @seealso lists related functions with informal descriptions. @family groups functions into a named family where each function automatically links to all others in the family. For a package with multiple related functions — all the string manipulation functions, all the import functions — @family creates navigable documentation networks.

Linking to functions in other packages uses the pkgname::function notation inside link{} tags. Linking to other functions in the same package omits the package name. Internal hyperlinks in HTML documentation are generated automatically from roxygen2 links, making it easy for users to navigate to related functions. Including links generously reduces the documentation’s dependency on users already knowing what other functions exist.

Next steps

Now that you understand documenting with roxygen2, explore these related topics to deepen your knowledge and apply these techniques in more complex scenarios.

See also