If you copy-paste the same function twice, it belongs in a package.
This creates the scaffolding for your package:
DESCRIPTION
NAMESPACE
R/
directory for code💡 Pro tip: Version control makes collaboration and rollback easier.
Using Git is great — but before you commit anything:
Even private Git repos are not fully secure.
Warning
Never commit:
Use .gitignore
to avoid tracking sensitive files:
You can also add .gitattributes
or .Rbuildignore
to prevent including files in your built package.
📁 DESCRIPTION - Metadata about your package
📁 NAMESPACE - Controls what functions are visible
📁 R/ - All your function files live here
📁 man/ - Auto-generated documentation
Every R package has a DESCRIPTION
file — it’s the package’s metadata.
Package: mypackage
Title: What the Package Does (One Line, Title Case)
Version: 0.0.0.9000
Authors@R: person("Your", "Name", email = "you@example.com", role = c("aut", "cre"))
Description: A longer description of what your package does.
License: MIT + file LICENSE
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.3
Field | What it does |
---|---|
Package |
The name of your package (must match folder name) |
Title |
One-sentence title (no period) |
Version |
Start with 0.0.0.9000 for dev |
Authors@R |
Who wrote the package |
Description |
Paragraph describing functionality |
License |
Licensing info (e.g., MIT, GPL-3) |
Imports |
Other packages your code uses |
Use Imports:
in DESCRIPTION
to declare which packages your functions rely on.
Don’t edit it by hand — use usethis::use_package()
:
This automatically adds to Imports:
and avoids typos.
Tip
Only list packages your code depends on directly.
Use Suggests:
for things like testing, vignettes, or optional features.
The NAMESPACE
tells R what to export to users and what to import from other packages.
Example (auto-generated):
🧠 If it’s not in NAMESPACE, users can’t use it — even if the function exists.
You rarely edit this file directly. Instead, let roxygen handle it.
Use: - @export
to add a function - @importFrom dplyr select
to import selectively
Then run:
This updates NAMESPACE
for you.
Tip
Internal helpers? Leave out @export
— they’ll stay private.
Create a new R script:
Then load your package into your session:
This mimics “installing” your package without needing to reinstall each time.
Tip
You’ll see add_numbers()
autocomplete in your session now!
✅ Works!
❌ No documentation yet!
#' Add two numbers
#'
#' @param x A number
#' @param y Another number
#' @return The sum of x and y
#' @export
add_numbers <- function(x, y) {
x + y
}
💡 Each line starts with
#'
and sits directly above the function.
NAMESPACE
.Rd
file in man/
?help
lookup✅ Now you’ll see formatted documentation!
✅ Still works!
This creates a data-raw/
folder and a script you can use to clean/load data.
# In data-raw/my_dataset.R
# Replace with your actual import code
my_dataset <- read.csv("path/to/your.csv")
usethis::use_data(my_dataset)
📦 Your data is now accessible via
my_dataset
when the package is loaded!
Like functions, you can document datasets using roxygen.
Create a new .R
file (e.g., R/data-documentation.R
) and add:
#' Example dataset: my_dataset
#'
#' This dataset contains example data imported from a CSV.
#'
#' @format A data frame with 100 rows and 5 variables:
#' \describe{
#' \item{col1}{Description of column 1}
#' \item{col2}{Description of column 2}
#' \item{col3}{Description of column 3}
#' }
#' @source Imported from a CSV file.
"my_dataset"
💡 The name in quotes at the end (
"my_dataset"
) must match the object name.
This will create a help file just like for functions.
You now get documentation in the help panel.
devtools::document() # Ensure docs are updated
devtools::check() # Run package checks
devtools::install() # Install locally
check()
will catch most common problems before they become bugs.
usethis::use_testthat()
for testingusethis::use_github()
usethis
cheatsheet: https://usethis.r-lib.orgdevtools
docs: https://devtools.r-lib.org