| name | cran-submission |
| description | Complete guide to CRAN submission including policies, pre-submission checks, common issues, and the submission process |
CRAN Submission Guide
This skill covers the complete CRAN submission process, from pre-submission preparation through to acceptance and post-release tasks. CRAN (Comprehensive R Archive Network) is the primary repository for R packages and has strict quality requirements.
Rules
- All exported functions must have
@returns and @examples documentation
- Version number must be greater than the current CRAN version
- Test on multiple platforms before submission (Windows, macOS, Linux, R-devel)
- Fix all ERRORs and WARNINGs - CRAN will reject packages with any
- NOTEs should be explained in cran-comments.md
- Title case for Title field with no period at the end, under 65 characters
- Use cph role for copyright holders in Authors@R
- Check all URLs with urlchecker::url_check()
- Examples must run without errors (use
\donttest{} sparingly)
- Respond to CRAN within 2 weeks or submission will be archived
Pre-Submission Checklist
Essential Documentation Requirements
Every exported function must have:
my_function <- function(x, y) {
}
Critical: Use @returns (not @return) for consistency with roxygen2 7.0+.
DESCRIPTION File Requirements
Package: packagename
Title: A Package That Does Amazing Things # Title case, < 65 chars, no period
Version: 0.1.0 # Must be > current CRAN version
Authors@R: c(
person("First", "Last", email = "email@example.com",
role = c("aut", "cre"),
comment = c(ORCID = "0000-0000-0000-0000")),
person("Another", "Author", role = "aut"),
person("Company Name", role = "cph") # Copyright holder
)
Description: Provides tools for amazing analysis. This package implements
novel algorithms and provides intuitive interfaces. Functions include
data processing, visualization, and reporting capabilities.
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.0
URL: https://username.github.io/packagename/, https://github.com/username/packagename
BugReports: https://github.com/username/packagename/issues
Suggests:
testthat (>= 3.0.0),
knitr,
rmarkdown
VignetteBuilder: knitr
Config/testthat/edition: 3
Title field rules:
- Title case (capitalize major words)
- No period at end
- Under 65 characters
- Don't start with "A Package for..." (redundant)
- Be specific about what it does
Description field rules:
- One paragraph
- Indent continuation lines with 4 spaces
- Don't start with "This package..."
- Explain what the package does, not just list features
- Mention key algorithms or papers if relevant
Version Numbering
For new submissions:
Version: 0.1.0
For updates (must be > CRAN version):
# If CRAN has 0.1.0, use:
Version: 0.1.1 # Bug fixes
Version: 0.2.0 # New features
Version: 1.0.0 # Major release
Development versions (not for CRAN):
Version: 0.1.0.9000 # Development version after 0.1.0
Multi-Platform Testing
Local Testing
devtools::check()
devtools::check(remote = TRUE, manual = TRUE)
devtools::check(args = c('--as-cran'))
Windows Testing
devtools::check_win_devel()
devtools::check_win_release()
devtools::check_win_oldrelease()
You'll receive an email with results in ~30 minutes.
R-hub Testing
install.packages("rhub")
rhub::validate_email()
rhub::check_for_cran()
rhub::check(platform = "windows-x86_64-devel")
rhub::check(platform = "ubuntu-gcc-release")
rhub::check(platform = "macos-highsierra-release-cran")
rhub::check(platform = "solaris-x86-patched")
rhub::platforms()
Note: R-hub can be unreliable. GitHub Actions with r-lib/actions is often more reliable.
GitHub Actions
Most reliable multi-platform testing:
usethis::use_github_action("check-standard")
Tests on:
- macOS (release)
- Windows (release)
- Ubuntu (devel, release, oldrel-1)
URL Checking
urlchecker::url_check()
Common issues:
- DOIs should use
https://doi.org/ not http://dx.doi.org/
- Use permanent URLs, not redirects
- Some URLs may be temporarily down (explain in cran-comments.md)
Creating cran-comments.md
Create cran-comments.md in package root:
## Test environments
* local R installation, R 4.4.0
* ubuntu 22.04 (on GitHub Actions), R-devel, R-release, R-oldrel-1
* windows-latest (on GitHub Actions), R-release
* macos-latest (on GitHub Actions), R-release
* win-builder (devel and release)
## R CMD check results
0 errors | 0 warnings | 1 note
* This is a new release.
## Downstream dependencies
There are currently no downstream dependencies for this package.
For Updates
## Test environments
* local R installation, R 4.4.0
* ubuntu 22.04 (on GitHub Actions), R-devel, R-release, R-oldrel-1
* windows-latest (on GitHub Actions), R-release
* macos-latest (on GitHub Actions), R-release
## R CMD check results
0 errors | 0 warnings | 0 notes
## What's changed
This is a minor release that fixes bugs and adds new features:
* Fixed issue with X (#123)
* Added new function Y
* Improved documentation for Z
## Downstream dependencies
I have run R CMD check on downstream dependencies of my package.
All packages passed.
Explaining NOTEs
## R CMD check results
0 errors | 0 warnings | 1 note
* Checking CRAN incoming feasibility ... NOTE
Maintainer: 'First Last <email@example.com>'
New submission
Possibly misspelled words in DESCRIPTION:
MCMC (3:49)
PyMC (9:31)
These are not misspelled:
* MCMC is a standard acronym for Markov Chain Monte Carlo
* PyMC is the name of a Python library
Submission Process
First Submission
devtools::check()
devtools::check_win_devel()
rhub::check_for_cran()
urlchecker::url_check()
devtools::build()
devtools::submit_cran()
Manual Submission
If submit_cran() doesn't work:
- Build package:
devtools::build()
- Go to https://cran.r-project.org/submit.html
- Upload .tar.gz file
- Fill in maintainer email and comments
- Submit
Confirmation Email
You'll receive an email asking to confirm submission:
- Click the confirmation link within 24 hours
- CRAN will then review your package
CRAN Review Process
Timeline
- Submission: Upload package
- Confirmation (immediate): Confirm via email
- Automated checks (minutes to hours): CRAN runs checks
- Human review (days to weeks): CRAN volunteer reviews
- Acceptance or rejection: Email notification
Typical timeline: 1-2 weeks, but can be longer during busy periods.
Common Rejection Reasons
- ERRORs or WARNINGs in R CMD check
- Missing documentation (no @returns or @examples)
- Examples fail or take too long (>5 seconds per example)
- License issues (incompatible or missing LICENSE file)
- DESCRIPTION problems (title, description formatting)
- Failed tests on CRAN's systems
- Large package size (>5 MB without justification)
- Writing to user's home directory without permission
- Internet resources without checks (must fail gracefully if offline)
- Non-standard file permissions
Common R CMD Check Issues and Fixes
1. Undefined Global Variables
Problem:
checking R code for possible problems ... NOTE
my_function: no visible binding for global variable 'x'
my_function: no visible binding for global variable 'y'
Cause: Using NSE (non-standard evaluation) with dplyr, data.table, etc.
Solution:
utils::globalVariables(c("x", "y", "z"))
library(dplyr)
my_function <- function(df) {
df %>%
mutate(z = .data$x + .data$y)
}
2. Unused Imports
Problem:
checking dependencies in R code ... NOTE
Namespace in Imports field not imported from: 'package'
Solution: Remove from DESCRIPTION or use somewhere:
3. Non-ASCII Characters
Problem:
checking R files for non-ASCII characters ... NOTE
Solution: Use Unicode escapes:
"Müller"
"M\u00fcller"
4. Examples Fail
Problem:
checking examples ... ERROR
Solution: Wrap problematic examples:
Rules:
\donttest{}: Runs locally and on CI, skipped on CRAN (for slow examples)
\dontrun{}: Never runs automatically (for examples needing setup)
- Don't overuse - most examples should run
5. Missing Imports
Problem:
checking dependencies in R code ... WARNING
'::' or ':::' imports not declared from:
'package'
Solution: Add to DESCRIPTION Imports and use:
Or declare in NAMESPACE:
importFrom(package, function)
6. LaTeX/PDF Errors
Problem:
checking PDF version of manual ... WARNING
Solution: Fix .Rd formatting issues or use:
build_args: 'c("--no-manual")'
7. Vignette Build Fails
Problem:
checking re-building of vignette outputs ... WARNING
Solution: Ensure vignettes build:
devtools::build_vignettes()
8. File Permissions
Problem:
checking file modes ... NOTE
Solution: Fix permissions:
chmod 644 R/*.R
chmod 644 man/*.Rd
chmod 755 configure
9. Package Size
Problem:
checking installed package size ... NOTE
installed size is X Mb
sub-directories of 1Mb or more:
data Y Mb
Solution:
- Compress data:
tools::resaveRdaFiles("data")
- Use
LazyData: true in DESCRIPTION
- Consider external data package
- Explain large size in cran-comments.md
10. Writing to User Directories
Problem: Package writes to home directory or modifies environment
Solution: Use temporary directories:
write.csv(data, "~/mypackage/output.csv")
tmpdir <- tempdir()
write.csv(data, file.path(tmpdir, "output.csv"))
config_dir <- tools::R_user_dir("mypackage", which = "config")
if (!dir.exists(config_dir)) {
dir.create(config_dir, recursive = TRUE)
}
11-20. Additional Common Issues
11. Suggested packages not declared:
if (requireNamespace("ggplot2", quietly = TRUE)) {
} else {
message("Install ggplot2 for better plots")
}
12. Internet resources without checks:
check_connection <- function(url) {
tryCatch({
httr::GET(url, httr::timeout(5))
TRUE
}, error = function(e) {
message("Cannot connect to ", url)
FALSE
})
}
13. Testing failures:
testthat::skip_on_cran()
testthat::skip_if_offline()
14. Long-running tests:
Sys.setenv("NOT_CRAN" = "true")
testthat::skip_on_cran()
15. Missing LICENSE file:
usethis::use_mit_license()
16. Undeclared S3 methods:
print.myclass <- function(x, ...) {
}
S3method(print, myclass)
17. Examples too long:
- Keep examples under 5 seconds each
- Use smaller datasets
- Wrap slow parts in
\donttest{}
18. Rd cross-references broken:
19. Non-standard installation:
- Don't require user interaction during installation
- Use
configure script for system dependencies
- Document requirements clearly
20. Archived dependencies:
- Check that all dependencies are on CRAN
- Update or remove archived dependencies
21-30. More Issues
21. Data documentation missing:
"dataset_name"
22. NAMESPACE conflicts:
internal_function <- function() {}
23. Windows path issues:
file.path("dir", "file.txt")
24. Encoding issues:
Add to DESCRIPTION:
Encoding: UTF-8
25. Undeclared attachments:
dplyr::filter()
26. Examples with \dontrun only:
- Every function needs runnable examples
- Use
\donttest{} instead of \dontrun{} when possible
27. Biased package names:
- Don't use "R" prefix (e.g., "Rpackage")
- Don't use misleading names
- Check name isn't trademarked
28. Missing return values:
29. Improper TRUE/FALSE:
if (condition == TRUE)
30. Unconventional directory structure:
- Follow standard R package structure
- No spaces in file names
- Use lowercase for .R files
31-50. Advanced Issues
31-40: Platform-specific code, parallel processing issues, memory leaks, C/C++ code problems, Fortran code issues, Java dependencies, system command calls, graphic device problems, locale-specific code, timezone issues
41-50: Partial argument matching, 1:length() issues, sapply() problems, dependency version constraints, circular dependencies, namespace pollution, documentation warnings, alias issues, keyword problems, cross-reference errors
Resubmission After Rejection
Responding to CRAN Comments
If rejected, you'll get an email with issues. Fix them and resubmit:
## Resubmission
This is a resubmission. In this version I have:
* Fixed the DESCRIPTION title to be in title case
* Added \value sections to all exported functions
* Ensured all examples run without errors
* Fixed the NOTE about global variables by using utils::globalVariables()
## Test environments
...
Important:
- Address ALL comments from CRAN
- Be polite and professional
- Explain what you changed
- Resubmit within 2 weeks
Version Bumping
After rejection, bump patch version:
# First submission
Version: 0.1.0
# After rejection
Version: 0.1.0 # Keep same version if resubmitting same release
# Or bump if making significant changes
Version: 0.1.1
Reverse Dependency Checking
If your package has downstream dependencies (packages that depend on yours):
install.packages("revdepcheck")
revdepcheck::revdep_check(num_workers = 4)
revdepcheck::revdep_report()
Post-Acceptance Tasks
After CRAN Acceptance
usethis::use_github_release()
usethis::use_dev_version()
Announce Release
- Tweet about it
- Post on R-bloggers
- Update website
- Email interested users
Monitor CRAN
Check CRAN check results daily:
https://cran.r-project.org/web/checks/check_results_PACKAGENAME.html
Fix any issues that arise on CRAN's servers.
Common Pitfalls
1. Submitting with WARNINGs
Problem: Package has warnings but submitter thinks they're acceptable
Fix: CRAN will auto-reject. Fix ALL warnings before submission.
2. Not Testing on Windows
Problem: Package works on Mac/Linux but fails on Windows
Fix: Use check_win_devel() and GitHub Actions before submission.
3. Examples That Require Setup
Problem: Examples assume files/data/authentication exist
Fix: Examples must be self-contained or use \dontrun{}.
4. Not Responding Quickly
Problem: Wait too long to respond to CRAN
Fix: Respond within 2 weeks or submission is archived.
5. Arguing with CRAN
Problem: Trying to argue that a NOTE is acceptable
Fix: Either fix it or provide a clear, technical explanation in cran-comments.md.
6. Incomplete Documentation
Problem: Missing @returns or @examples
Fix: Every exported function needs both.
7. Version Confusion
Problem: Trying to submit 0.1.0 when CRAN has 0.1.0
Fix: Bump version to 0.1.1 or higher.
8. Large Package Size
Problem: Package is 10+ MB
Fix: Compress data, use external data, or justify in cran-comments.md.
9. Too Many Imports
Problem: Importing 20+ packages
Fix: Consider if all are necessary. Each import is a dependency burden.
10. Not Reading CRAN Policies
Problem: Violating policies unknowingly
Fix: Read https://cran.r-project.org/web/packages/policies.html
Final Pre-Submission Checklist
Good luck with your CRAN submission!