Documenting Functions with roxygen2
Write @param, @return, @examples, and @export tags for automatic docs.
Documenting Functions with roxygen2 is a free R Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the R Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Is roxygen2?
roxygen2 lets you write R documentation directly above your function as specially formatted comments starting with #'. When you run devtools::document(), roxygen2 parses these comments and generates man/*.Rd files and updates NAMESPACE automatically.
The Minimal roxygen2 Block
The simplest documentation block needs at least a title and description. The first sentence (up to the first period or blank line) becomes the title. Subsequent paragraphs become the description.
# R/add.R
#
# #' Add two numbers
# #'
# #' Computes the sum of x and y. Both arguments must be numeric.
# #'
# #' @export
# add <- function(x, y) {
# x + y
# }@title and @description Tags
Use explicit @title and @description tags when the first-paragraph convention is not enough — for example, when the title must differ from the function name or the description is multi-paragraph.
# #' @title Safe Addition of Numeric Values
# #' @description
# #' Adds two numeric vectors element-wise.
# #' Returns NA where either input is NA.
# #' Useful for financial calculations where NA propagation matters.
# #'
# #' @export
# add <- function(x, y) {
# x + y
# }@param — Documenting Arguments
#' @param name Description documents one function argument. Use one @param line per argument. The description should state the expected type and what the argument controls.
# #' Add two numbers
# #'
# #' @param x A numeric vector. The first operand.
# #' @param y A numeric vector. The second operand. Must be the same length as x
# #' or length 1 (recycled).
# #'
# #' @export
# add <- function(x, y) {
# if (!is.numeric(x) || !is.numeric(y)) stop('x and y must be numeric')
# x + y
# }@return — Documenting the Return Value
#' @return Description describes what the function returns. State the type, class, and structure of the return value. This is required for CRAN submission.
# #' Add two numbers
# #'
# #' @param x A numeric vector.
# #' @param y A numeric vector.
# #' @return A numeric vector of the same length as the longer of x or y,
# #' containing the element-wise sums.
# #'
# #' @export
# add <- function(x, y) x + y@examples — Runnable Code Examples
#' @examples provides code that appears in the help page and is run by R CMD check. Examples must complete in under 5 seconds and not require external resources (network, files). Each line is regular R code — no special prefixes needed.
# #' Add two numbers
# #'
# #' @param x A numeric vector.
# #' @param y A numeric vector.
# #' @return A numeric vector of element-wise sums.
# #' @examples
# #' add(1, 2)
# #' add(c(1, 2, 3), c(10, 20, 30))
# #' add(0, -5)
# #' @export
# add <- function(x, y) x + y@export — Making Functions Public
#' @export tells roxygen2 to add the function to NAMESPACE, making it available to users of your package. Functions without @export are internal — they can be called within the package but not by users (without :::).
# Public function — exported:
# #' @export
# add <- function(x, y) x + y
#
# Internal helper — not exported:
# check_numeric <- function(x) {
# if (!is.numeric(x)) stop('Expected numeric')
# }
#
# After devtools::document(), NAMESPACE will contain:
# export(add)
# but NOT check_numeric@importFrom — Importing Functions
#' @importFrom pkg fn1 fn2 imports specific functions from a package into your namespace so you can call them without the pkg:: prefix. Use sparingly — explicit pkg::fn() is clearer and avoids namespace pollution.
# Option 1 — @importFrom (adds to NAMESPACE, no pkg:: needed):
# #' @importFrom stringr str_trim str_to_lower
# clean <- function(x) str_to_lower(str_trim(x))
#
# Option 2 — explicit :: (recommended for clarity):
# clean <- function(x) {
# stringr::str_to_lower(stringr::str_trim(x))
# }
#
# Both work; prefer Option 2 to keep NAMESPACE minimaldevtools::document() Workflow
After editing roxygen2 comments, call devtools::document() (Ctrl+Shift+D) to regenerate man/*.Rd and update NAMESPACE. Then view the help page with ?add (after load_all()) to confirm it looks correct.
# Full documentation cycle:
# 1. Edit roxygen2 comments in R/add.R
# 2. devtools::document() # regenerate man/ and NAMESPACE
# 3. devtools::load_all() # reload package
# 4. ?add # preview the help page
# 5. devtools::check() # ensure no documentation errorsDocumenting Multiple Functions on One Page
Use #' @rdname shared_name to merge multiple related functions onto a single help page. The primary function gets the full roxygen2 block; secondary functions get only @rdname and @export.
# R/arithmetic.R
#
# #' Basic Arithmetic
# #' @param x,y Numeric vectors.
# #' @return A numeric vector.
# #' @examples
# #' add(1, 2); subtract(5, 3)
# #' @export
# add <- function(x, y) x + y
#
# #' @rdname add
# #' @export
# subtract <- function(x, y) x - yOther Useful Tags
Additional roxygen2 tags for complete documentation:
#' @seealso \code{\link{other_fn}}— cross-reference#' @note— extra notes after description#' @author Name— function author#' @keywords internal— hides from package index but keeps help page#' @family group_name— groups related functions in help
# #' Add two numbers
# #' @param x,y Numeric vectors.
# #' @return Numeric vector.
# #' @seealso \code{\link{subtract}} for the inverse operation.
# #' @family arithmetic
# #' @examples
# #' add(1, 1)
# #' @export
# add <- function(x, y) x + yQuick Check: @export Tag
What happens to a function in an R package that has roxygen2 documentation but NO #' @export tag?
roxygen2 Documentation Recap
Core roxygen2 tags for complete R package documentation:
#' @title/ first line — function title#' @description— detailed description#' @param name Description— document each argument#' @return Description— describe return value#' @examples \n code— runnable examples (checked by R CMD check)#' @export— add to NAMESPACE (makes function public)#' @importFrom pkg fn— import specific functions- Run
devtools::document()to regenerate man/ and NAMESPACE
Frequently asked questions
Is the “Documenting Functions with roxygen2” lesson free?
Yes — the full text of “Documenting Functions with roxygen2” is free to read here on the web, and the R Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the R Academy course, upgrade to CoddyKit PRO.
What will I learn in “Documenting Functions with roxygen2”?
Write @param, @return, @examples, and @export tags for automatic docs. You practise R Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start R Academy?
No prior experience is required. R Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Documenting Functions with roxygen2” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this R Academy lesson?
Yes. Every R Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Package Structure with usethis and devtools
- Documenting Functions with roxygen2
- Unit Testing with testthat
- CRAN Submission and Package Maintenance