roxygen2: writing R documentation next to the code it describes
Generate R package documentation from inline R comments
At a glance
- What is it?
- roxygen2 is the R package that turns inline comments into the .Rd files, NAMESPACE and Collate field that R itself reads, so documentation lives in the same file as the function it documents. The trade-off is that the generated files are build artefacts you must not edit by hand, and the README is explicit about the vignettes you need for each kind of object.
- Who is it for?
- Adopt roxygen2 if you maintain an R package and want the documentation to live next to the code, because hand written .Rd files drift from the code and roxygen2 removes that class of bug. Do not adopt it if your project is a set of loose scripts with no package structure, since there is nothing to generate into.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly R, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The premise: comments in, Rd files out
The README states the premise in one sentence. You describe your functions in comments next to their definitions, and roxygen2 processes your source code and comments to automatically generate .Rd files in man/, a NAMESPACE file, and, if needed, the Collate field in DESCRIPTION.
That list of outputs is the whole value proposition, and it is worth separating the three. The .Rd files are what R renders when a user types ?str_length. The NAMESPACE file is what R uses to decide which objects a package exports and which it imports. The Collate field is the order in which R loads your source files, which matters when a package has load order dependencies between its R files.
The problem this solves is drift. If documentation is written in a separate .Rd file, it sits in a different file from the function, and the two can disagree about argument names and defaults without anything complaining. When the documentation is a comment block two lines above the function signature, the compiler of that documentation is the same edit as the code.
The audience is R package authors, and specifically the kind of package where the public API is stable enough that the reference manual is part of the product. A script repository with three functions does not need this machinery.
The project is hosted at roxygen2.r-lib.org, the primary language is R, and the last push to the repository was on 2026-10-09, the same day as the newest release.
Installation from CRAN, or the development version through pak
Installation is the shortest section in the README, and it covers both the stable and the development route:
# Install roxygen2 from CRAN
install.packages("roxygen2")
# Or the development version from GitHub:
# install.packages("pak")
pak::pak("r-lib/roxygen2")The second route needs pak installed first, and pak is itself the package manager for R, so the development install is a two step: install pak, then point it at the GitHub repository. That is a deliberate choice rather than a raw remotes install, because pak resolves and installs the dependencies of the development version, which a plain install from a URL does not do for you.
The first real use is a call to roxygenise(), or equivalently devtools::document(). When you run it, the comment blocks above your functions are transformed into the .Rd files that R uses for the help pages you see when you type ?str_length.
The key mental adjustment is that the .Rd files in man/ and the NAMESPACE file are outputs. They are regenerated, and the README's own layout shows a man/ directory and a NAMESPACE file sitting in a repository that also contains the R/ directory the comments actually live in. A reviewer looking at the diff of a pull request will see the .Rd changes alongside the R changes, and that is the point: the documentation change is visible in the same commit as the code change it describes.
What a documented function actually looks like
The README's example comes from the stringr package, and it is worth reading in full because it shows the tag vocabulary.
The block is a sequence of roxygen tags. A @inheritParams tag pulls the parameter documentation for str_detect from that other function rather than repeating it. A @return tag describes the return value. A @seealso tag cross references a related function, here stringi::stri_length(). An @export tag marks the function for export, and the @examples tag provides runnable example lines that end up in the help page.
The example also shows the convention of the comment block immediately preceding the function definition, with the function signature right below it:
#' @export
#' @examples
#' str_length(letters)
#' str_length(NA)
#' str_length(factor("abc"))
#' str_length(c("i", "like", "programming", NA))
str_length <- function(string) {
}The examples in that block are not decoration. R runs them during package checks, so an example that errors is a check failure rather than a documentation bug that nobody notices.
The @inheritParams mechanism is the part that changes how you write. If several functions take the same argument with the same meaning, the description is written once and inherited, so the copy cannot drift. It is the same argument as roxygen2's, in a smaller scope, and it is why the example borrows from str_detect instead of restating what a string is.
The vignettes are the actual manual
The README does not attempt to document the tag set inline. It points at a vignette per topic, and the list is the documentation map for the project.
The starting point is vignette("roxygen2"). From there, vignette("rd-functions") covers documenting functions. The OOP systems each have their own: vignette("rd-S3"), vignette("rd-S4"), vignette("rd-R6") and vignette("rd-S7"). Datasets and the package itself are covered by vignette("rd-datasets") and vignette("rd-packages"). Formatting is vignette("rd-formatting"), which gives the details of the rmarkdown support. Reuse is vignette("reuse"), which demonstrates the tools available to reuse documentation in multiple places, and vignette("namespace") describes how to generate a NAMESPACE file, how namespacing works in R, and how you can use roxygen2 to be specific about what your package needs and supplies.
The last entry is separate: for the Collate field in the DESCRIPTION, the README sends you to ?update_collate().
The separate treatment of the NAMESPACE and Collate topics is the signal about where the complexity lives. Writing function documentation is straightforward. Deciding what your package exports and imports is a policy question, and roxygen2 will write the NAMESPACE file exactly as you tell it to, which is helpful when the policy is right and unhelpful when it is wrong. The same is true of Collate: generating the field is easy, and knowing whether you need it is a decision about your package's load order.
Maintenance, versioning and the shape of the repository
The release history shows a project on a steady annual major cycle. The tags are v8.1.1 on 2026-10-09, v8.0.0 on 2026-05-01 and v8.1.0 on 2026-08-04, so the 8.x line has already had a minor release after the major, and the last push to the repository was on 2026-10-09, the same day as the newest tag.
For a package that many other packages depend on for their own build, that cadence matters more than it would for an application. A new major version of roxygen2 is a new major version for every package that regenerates its documentation, and the vignettes are where the changes are described.
The repository layout is a standard R package with the tooling a mature R project accumulates. There is a DESCRIPTION file, a NAMESPACE file, a LICENSE and a separate LICENSE.md, an R directory for the sources, a man directory for the generated .Rd files, an inst directory, a src directory, a tests directory and a vignettes directory for the documentation topics listed above. Around that sit the development files: a .Rbuildignore, a .covrignore for coverage exclusions, a .devcontainer, a .vscode directory, an _pkgdown.yml for the site, a panache.toml and an air.toml for formatting, a codecov.yml, a cran-comments.md, an AGENTS.md and a revdep directory for reverse dependency checks.
The licence situation needs a note. The platform metadata classifies the licence as a custom one that it cannot categorise, while the repository carries both a LICENSE and a LICENSE.md file, so the actual terms are in those files rather than in a badge. That is normal for R projects, where the licence is often a standard licence with an additional note about the package or its documentation, and it is worth reading before you copy the convention into your own package.
Where roxygen2 is the wrong tool
The boundary is package shaped. roxygen2 needs a package structure, a DESCRIPTION file and a man/ directory to write into, so an analysis script directory, a Shiny app without a package skeleton, or a collection of functions sourced ad hoc gets no benefit from it and gains a dependency it does not need.
The second boundary is that generated files must not be edited by hand. A .Rd file that someone tweaked directly will be silently overwritten the next time someone runs roxygenise(), and the hand edit is lost without an error. Teams that come from a hand written .Rd workflow hit this hard, and the transition period is when documentation changes get lost.
The third is the one that generates the most argument in practice. A roxygen block is R source code, so it is versioned, diffed and reviewed like code, and a reviewer has to read R comments to see what the documentation says. That is exactly the point for some teams, and exactly the wrong workflow for teams whose documentation reviewers do not read R. The generated .Rd is what a writer sees, and the two audiences are served by different files from the same source.
There is also a cost in what the tags allow. roxygen2 can express the documentation R's help system can render, which is a fixed and not especially expressive target, and a package that needs rich narrative documentation still has to write prose, with the tags only pointing at the right file. The vignettes listed in the README are where the boundary is drawn, and the reuse vignette exists precisely because a growing package ends up needing the same paragraph in several places.
Editorial conclusion
Adopt roxygen2 if you maintain an R package and want the documentation to live next to the code, because hand written .Rd files drift from the code and roxygen2 removes that class of bug. Do not adopt it if your project is a set of loose scripts with no package structure, since there is nothing to generate into. Verify first which roxygen2 major version your package expects, since 8.0.0 landed on 2026-05-01 and the vignette list has grown over time, read vignette("namespace") before letting it write your NAMESPACE file, and check the Collate field behaviour with ?update_collate() if your package relies on a specific collation order.
Frequently asked questions
What does roxygen2 do?
It processes R source files and the comments next to your function definitions to generate .Rd files in man/, a NAMESPACE file and, if needed, the Collate field in DESCRIPTION. The generated .Rd is what R renders when you type ?function_name.
How do I install roxygen2?
From CRAN with install.packages("roxygen2"), or the development version from GitHub by installing pak and then running pak::pak("r-lib/roxygen2"). After installation you run roxygenise(), or devtools::document(), to generate the documentation.
Which R objects can roxygen2 document?
Functions, the S3, S4, R6 and S7 object systems, datasets and the package itself, each covered by its own vignette: rd-functions, rd-S3, rd-S4, rd-R6, rd-S7, rd-datasets and rd-packages. There is also vignette("namespace") for generating a NAMESPACE file and ?update_collate() for the DESCRIPTION Collate field.
Should I edit the generated Rd files by hand?
No. The man/ directory and the NAMESPACE file are regenerated by roxygenise(), so manual edits to them are lost the next time the documentation is rebuilt. The README does not spell this out, but it follows from the premise that these files are outputs of the comments in your R sources.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/r-lib-roxygen2)Was this useful?