ruraldefinitions
R package aggregating federal rural definitions and making them accessible to R programmers. County-level definitions are bundled as package data; tract-level definitions are loaded from S3 via get_definition(). Supports CBSA, RUCC, NCHS, UIC, RUCA, and CORI rural classifications across multiple vintages.
Drew Rosebush 2026-08-31
Overview
The ruraldefinitions package aggregates federal rural classification systems and makes them accessible in R without manual downloads or crosswalk construction. County-level definitions are bundled directly as package data — accessible immediately after loading the package. Tract- and block-level definitions are available via get_definition(), which reads from an S3 bucket.
The package supports seven classification systems across multiple vintages: the CORI definition, CBSA metropolitan/micropolitan delineations, USDA Rural-Urban Commuting Area (RUCA) codes, USDA Rural-Urban Continuum Codes (RUCC), USDA Urban Influence Codes (UIC), National Center for Health Statistics (NCHS) classification, and the Census Bureau’s block-level rural definition. Every other cori.data.* package uses ruraldefinitions to attach rural/nonrural flags to analysis datasets.
Installation & quick start
remotes::install_github("ruralinnovation/ruraldefinitions")
library(ruraldefinitions)
# County-level definitions — available directly as package data
head(cbsa_2023) # CBSA 2023 (CORI standard for county analysis)
head(rucc_2023) # USDA Rural-Urban Continuum Codes 2023
head(nchs_2023) # NCHS Urban-Rural Classification 2023
head(uic_2024) # USDA Urban Influence Codes 2024
# Tract-level definitions — loaded from S3
cori_def <- get_definition("cori", 2020) # CORI hybrid definition
ruca_def <- get_definition("ruca", 2020) # USDA RUCA codes
# Attach rural flag to any county-level dataset
library(dplyr)
my_data |>
left_join(select(cbsa_2023, geoid, is_rural), by = "geoid")
What this data tells us about rural America
“Rural” is not a single definition. The federal government uses multiple classification systems — CBSA metropolitan/micropolitan delineations, USDA Rural-Urban Continuum Codes, NCHS Urban-Rural Classification, USDA Urban Influence Codes — each designed for different purposes and drawing the rural/nonrural boundary in different places. A county classified as rural under one system may not be under another. Researchers who select a definition without considering what it measures risk drawing conclusions that reflect the classification rather than the underlying reality.
CORI’s standard for county-level economic analysis is the CBSA-based definition (OMB metropolitan/micropolitan delineations), which classifies counties as rural if they fall outside a Core-Based Statistical Area. This definition is appropriate for most economic analysis because it reflects labor market integration — counties inside CBSAs have economic ties to urban cores that counties outside do not. It is not the only valid choice: USDA’s Rural-Urban Continuum Codes offer a gradient rather than a binary, capturing the range from completely rural to adjacent to large metro; the NCHS classification is designed specifically for health research contexts.
The choice of definition is a methodological decision with real consequences. CORI’s research documents patterns that differ between rural and nonrural counties — in employment composition, broadband coverage, business formation, and capital access — but the magnitude and the set of counties involved vary depending on which definition is applied. Making that choice explicit and defensible is part of credible rural analysis.
One additional dimension the data makes visible: the misconception that rural communities are homogeneously white renders people of color invisible in data, policy, and practice. Rural communities include significant Black, Hispanic, Native American, and Asian populations whose experiences and economic assets are not captured in analyses that treat rural as a monolithic category. Rural classifications are most useful when paired with demographic data, not used as a substitute for it.
Available definitions
County-level definitions are bundled as package data and available immediately. Tract-level definitions are accessed via get_definition().
| Name | Year(s) | Geographic Unit | Notes |
|---|---|---|---|
| CORI | 2010, 2020 | Tract | RUCA + CBSA hybrid — CORI’s standard for tract-level analysis |
| CBSA | 2018, 2020, 2023 | County | OMB metro/micro delineations — CORI’s standard for county-level analysis |
| RUCC | 1974–2023 | County | USDA gradient from metro to most rural |
| NCHS | 1990–2023 | County | Designed for health research contexts |
| UIC | 1993–2024 | County | USDA classification by urbanization and metro adjacency |
| RUCA | 1990–2020 | Tract | USDA commuting-based tract classification |
| Census | 2010, 2020 | Block | Census Bureau block-level definition |
Selecting a definition
For county-level economic analysis, CORI recommends cbsa_2023. If you have access to tract data and need to capture rural tracts within metro counties, use the CORI definition via get_definition("cori", 2020).
# CORI standard: county-level rural flag
rural_xwalk <- cbsa_2023 |>
dplyr::select(geoid, is_rural)
# Tract-level: includes rural tracts inside metro counties
cori_tract <- get_definition("cori", 2020)
CORI’s published guidance on definition selection: - Defining Rural America - Do No Harm Guide — Urban Institute writeup on crafting equitable data narratives
Definition maps
Adapted from the Rural Definitions Maps vignette on GitHub. See the full vignette for maps of all six definitions.
The following examples show how to map rural definitions using sf and tigris. All maps use the same county and state geometries loaded once and reused.
library(ruraldefinitions)
library(cori.charts)
library(dplyr)
library(ggplot2)
library(sf)
library(tigris)
load_fonts()
options(tigris_use_cache = TRUE)
# Load geometries once
counties_sf <- tigris::counties(cb = TRUE, year = 2023) |>
tigris::shift_geometry() |>
filter(GEOID <= "57") |>
sf::st_transform(crs = 5070)
states_sf <- tigris::states(cb = TRUE, year = 2023) |>
tigris::shift_geometry() |>
filter(GEOID <= "57") |>
sf::st_transform(crs = 5070)
bbox <- sf::st_bbox(states_sf)
CBSA 2023 — CORI’s county standard
colors_cbsa <- c(
"Metro" = cori_colors[["Dark Purple"]],
"Micro" = "#086656",
"Non-CBSA" = cori_colors[["Emerald"]]
)
map_cbsa <- counties_sf |>
left_join(cbsa_2023, by = c("GEOID" = "geoid")) |>
mutate(rural_def = factor(rural_def, levels = names(colors_cbsa))) |>
group_by(rural_def) |>
summarise(geometry = sf::st_union(geometry), .groups = "drop")
ggplot() +
geom_sf(data = map_cbsa, aes(fill = rural_def), color = NA) +
geom_sf(data = states_sf, fill = NA, color = "black", linewidth = 0.3) +
scale_fill_manual(name = NULL, values = colors_cbsa, na.value = "#ffffff") +
coord_sf(xlim = c(bbox["xmin"], bbox["xmax"]),
ylim = c(bbox["ymin"], bbox["ymax"]), expand = FALSE) +
labs(
title = "Core-Based Statistical Areas (CBSA), 2023",
subtitle = "County-level OMB metropolitan/micropolitan delineation",
caption = "Source: U.S. Office of Management and Budget, 2023 delineations."
) +
theme_cori_map() +
theme(legend.position = "top", legend.direction = "horizontal")
CORI 2020 — tract-level hybrid definition
state_fips <- tigris::fips_codes |>
dplyr::distinct(state_code) |>
dplyr::filter(state_code <= "56") |>
dplyr::pull(state_code)
tracts_sf <- purrr::map_dfr(
state_fips,
~tigris::tracts(state = .x, cb = TRUE, year = 2020, progress_bar = FALSE)
) |>
tigris::shift_geometry() |>
sf::st_transform(crs = 5070)
cori_raw <- get_definition("cori", 2020)
colors_cori <- c(
"Metro" = cori_colors[["Dark Purple"]],
"Nonmetro/RUCA 4+ carveouts" = cori_colors[["Emerald"]]
)
map_cori <- tracts_sf |>
left_join(cori_raw, by = c("GEOID" = "geoid")) |>
filter(!is.na(rural_def)) |>
mutate(
display = case_when(
rural_def == "Metro county" ~ "Metro",
rural_def %in% c("Nonmetro county",
"Rural tract in metro county") ~ "Nonmetro/RUCA 4+ carveouts"
),
display = factor(display, levels = names(colors_cori))
) |>
group_by(display) |>
summarise(geometry = sf::st_union(geometry), .groups = "drop")
ggplot() +
geom_sf(data = map_cori, aes(fill = display), color = NA) +
geom_sf(data = states_sf, fill = NA, color = "black", linewidth = 0.3) +
scale_fill_manual(name = NULL, values = colors_cori, na.value = "#ffffff") +
coord_sf(xlim = c(bbox["xmin"], bbox["xmax"]),
ylim = c(bbox["ymin"], bbox["ymax"]), expand = FALSE) +
labs(
title = "CORI Rural Definition, 2020",
subtitle = "Nonmetro counties (CBSA 2023) plus rural tracts (RUCA 4+) in metro counties",
caption = "Source: Center on Rural Innovation."
) +
theme_cori_map() +
theme(legend.position = "top", legend.direction = "horizontal")
Related
- Package: cori.data — meta-package that includes
ruraldefinitions - Dataset: USDA County Typology — further characterizes rural counties by economic and demographic type