Package Imports and Namespace Management
Guide to properly importing functions from other packages and managing your package’s namespace.
The NAMESPACE File
The NAMESPACE file controls: - Which functions your package exports (makes available to users) - Which functions your package imports from other packages
Important: Never edit NAMESPACE directly. Let roxygen2 generate it via devtools::document().
Package-Level Documentation
Create a package-level documentation file to declare imports.
Create R/{packagename}-package.R
#' @keywords internal
#' @importFrom stats weighted.mean
"_PACKAGE"
## usethis namespace: start
## usethis namespace: end
NULLReplace {packagename} with your actual package name (e.g., R/mymetrics-package.R).
What this does
@keywords internal- Marks as internal documentation@importFrom stats weighted.mean- Importsweighted.meanfrom stats"_PACKAGE"- Roxygen directive for package-level docs## usethis namespace:- Markers for usethis to add content
Common Import Patterns
Importing specific functions
#' @keywords internal
#' @importFrom stats weighted.mean median sd
#' @importFrom utils head tail
"_PACKAGE"Importing entire packages (use sparingly)
#' @keywords internal
#' @import rlang
"_PACKAGE"Warning: @import imports everything from a package. Use @importFrom instead to import only what you need.
When to Add Imports
R CMD check warnings
If you see warnings like:
checking R code for possible problems ... NOTE
your_function: no visible global function definition for 'weighted.mean'
Undefined global functions or variables:
weighted.mean
Solution: Add import to package-level doc:
#' @importFrom stats weighted.meanCommon packages that need imports
From stats:
#' @importFrom stats weighted.mean median sd var quantileFrom utils:
#' @importFrom utils head tail strFrom grDevices:
#' @importFrom grDevices rainbowDependencies in DESCRIPTION
Imports in NAMESPACE must match dependencies in DESCRIPTION.
Add package dependencies
# For packages you import from
usethis::use_package("rlang")
usethis::use_package("cli")
usethis::use_package("yardstick")
# For optional dependencies (examples, vignettes)
usethis::use_package("ggplot2", type = "Suggests")
usethis::use_package("modeldata", type = "Suggests")This updates DESCRIPTION:
Imports:
rlang,
cli,
yardstick
Suggests:
ggplot2,
modeldata
Calling Functions from Other Packages
Option 1: Use :: notation (recommended for occasional use)
# Don't need to import, just use ::
result <- dplyr::filter(data, condition)When to use: - Functions used infrequently - Clarity about where function comes from - Avoiding namespace conflicts
Option 2: Import and use directly (recommended for frequent use)
# In R/{packagename}-package.R
#' @importFrom dplyr filter mutate
# In your function code
result <- filter(data, condition) |>
mutate(new_col = old_col * 2)When to use: - Functions used frequently - Cleaner, more readable code - Functions are core to your package
Special Cases
Non-standard evaluation (NSE) with tidy eval
For rlang functions:
#' @keywords internal
#' @importFrom rlang := !! !!! enquo enquos sym syms
"_PACKAGE"S3 method registration
If you create S3 methods for other packages’ generics:
#' @export
#' @method autoplot your_class
autoplot.your_class <- function(object, ...) {
# Implementation
}Or use @export on the method:
#' @export
autoplot.your_class <- function(object, ...) {
# Implementation
}Importing entire packages (last resort)
Only use @import for packages designed for it (like rlang):
#' @keywords internal
#' @import rlang
"_PACKAGE"Avoid @import for most packages - import specific functions instead.
Workflow
Add dependency to DESCRIPTION:
usethis::use_package("dplyr")Add import to package-level doc:
#' @importFrom dplyr filter mutateUpdate documentation:
devtools::document()Use function in your code:
result <- filter(data, condition)
Common Issues
“could not find function”
Problem: Function not imported or package not in DESCRIPTION
Solution: 1. Add package to DESCRIPTION: usethis::use_package("package_name") 2. Add import or use :: notation 3. Run devtools::document()
“no visible global function definition”
Problem: Function used but not imported
Solution: Add @importFrom to package-level doc
“no visible binding for global variable”
Problem: NSE variables not declared (common with dplyr/ggplot2)
Solution: Either: - Use .data$column pronoun: mutate(.data$new_col = value) - Or add utils::globalVariables() to package-level doc: r utils::globalVariables(c("column_name", "another_column"))
“object is not exported by ‘namespace:package’”
Problem: Trying to import internal function
Solution: Use ::: (not recommended for production) or find an exported alternative
Best Practices
DO:
- Use
@importFromto import specific functions - Add all packages to DESCRIPTION first
- Run
devtools::document()after changes - Use
::for infrequently-used functions
DON’T:
- Edit NAMESPACE directly
- Use
@importfor most packages - Import internal functions with
::: - Forget to add packages to DESCRIPTION
Example Package-Level Doc
#' @keywords internal
#' @importFrom stats weighted.mean median sd
#' @importFrom rlang := !! enquo enquos
#' @importFrom cli cli_abort cli_warn
"_PACKAGE"
## usethis namespace: start
## usethis namespace: end
NULLChecking Your Imports
Run R CMD check to verify:
devtools::check()Look for: - “no visible global function definition” - add import - “Namespace dependencies not required” - remove import - “All declared Imports should be used” - remove unused package
Next Steps
- Write roxygen documentation: package-roxygen-documentation.md
- Follow best practices: package-extension-requirements.md#best-practices
- Set up testing: package-extension-requirements.md#testing-requirements