cori.data
CORI's rural data ecosystem — a family of R packages providing unified access to employment, population, business, housing, and broadband data across rural America
Mapping & Data Analytics Team 2026-08-27
Overview
cori.data is the meta-package for CORI’s rural data ecosystem — a growing collection of R packages providing unified access to employment, population, business, housing, and broadband data across rural America. Installing it pulls in every companion package; loading it attaches them all, so get_employment(), get_population(), get_definition(), and more are available without separate library() calls.
Not all federal data sources are designed with rural communities in mind. CORI’s data team has done the methodological work — identifying the right sources, applying consistent rural classifications, and packaging data in a format that works across rural geographies — so analysts can focus on the research question, not the data infrastructure.
Installation & quick start
remotes::install_github("ruralinnovation/cori.data")
library(cori.data)
# Employment, population, and business dynamics —
# all joinable on geoid + year, ready in minutes
get_employment(geography = "county", years = 2019:2023)
get_population(geography = "county", years = 2019:2023)
get_business_dynamics(geography = "county", years = 2019:2023)
The ecosystem
| Package | What it measures | Geography | Years |
|---|---|---|---|
| cori.data.qcew | Employment & wages (BLS QCEW) | county, state | 1990–present |
| cori.data.bds | Business dynamics (Census BDS) | county, state, nation | 1978–present |
| cori.data.pep | Population (Census PEP) | county, state, nation | 2000–present |
| cori.data.bfs | Business applications (Census BFS) | county, state, nation | 2004–present |
| cori.data.bps | Building permits (Census BPS) | county, state, nation | 2000–present |
| cori.data.hu | Housing units (Census HU) | county, state, nation | 2000–present |
| cori.data.fcc | Broadband coverage (FCC NBM) | county | 2022–present |
| ruraldefinitions | Rural classifications (OMB, USDA ERS, NCHS) | county | multiple vintages |
What this data tells us about rural America
Rural economies are diverse, complex, and deeply shaped by the assets and advantages they have accumulated over time: natural resources, agricultural land, industrial infrastructure, geographic position, community institutions, and workforce traditions. Some rural communities are thriving, leveraging those assets in new ways as remote work, entrepreneurship, and targeted investments. Others are navigating structural transitions as legacy industries shift. What they share is a foundation of real assets whose value in the modern economy depends on the conditions surrounding them.
Understanding which assets a community holds, how those assets connect to current economic conditions, and what they might support going forward requires data that spans multiple dimensions simultaneously. Employment trends read alongside business formation rates, population dynamics, broadband coverage, and sector composition tell a richer story than any single source alone. Across CORI’s research, communities with strong asset bases across multiple dimensions tend to show more resilient economic trajectories than those concentrated in a single advantage — and human capital, quality of life, and the capacity to retain and attract working-age residents consistently emerge as important complements to physical infrastructure.
The ecosystem exists because these questions require data that is consistent, joinable, and contextualized for rural analysis — and because the methodological decisions that make cross-source rural analysis tractable (which rural definition to apply, how to weight aggregations across counties of very different sizes, which sector taxonomy to use) are embedded in the packages rather than left to each researcher to reinvent.
Getting started
Adapted from the Getting Started vignette on GitHub.
A consistent interface
Every package uses the same four parameters. Learn the pattern once and it works everywhere:
library(cori.data.qcew)
library(cori.data.pep)
library(cori.data.bds)
# geography = "county", "state", or "nation"
# geoids = character vector of FIPS codes (overrides geography)
# years = integer vector of years
# variables = which variables to return (NULL = all)
get_employment(geography = "county", years = 2019:2023)
get_population(geography = "county", years = 2019:2023)
get_business_dynamics(geography = "county", years = 2019:2023)
# Filter to specific places with FIPS codes
get_employment(geoids = c("33009", "54011", "30001"), years = 2019:2023)
All functions return tidy (long) format data — one row per geoid × year × variable:
geoid year variable value
33009 2023 employment 28450
33009 2022 employment 27810
54011 2023 employment 12340Your first pull
library(cori.data.qcew)
library(dplyr)
emp <- get_employment(geography = "county", years = 2019:2023)
glimpse(emp)
# Which counties had the most employment in 2023?
emp |>
filter(year == 2023) |>
slice_max(value, n = 10)
Rural classifications
The ruraldefinitions package provides county-level rural/nonrural classifications across several methodologies. CORI’s standard for county analysis is the CBSA-based definition:
library(ruraldefinitions)
# CBSA-based (the CORI standard) — pre-loaded, no function call needed
rural <- cbsa_2023
# Returns: geoid | name | year | rural_def | is_rural ("Rural" / "Nonrural")
# Other available county-level definitions
rucc_2023 # USDA Rural-Urban Continuum Codes
nchs_2023 # NCHS Urban-Rural Classification Scheme
uic_2024 # USDA Urban Influence Codes
Working with tidy data
Adapted from the Working with Tidy Data vignette on GitHub.
The most powerful analyses come from combining packages — employment with population, business formation with building permits, broadband with wages. What makes that combination frictionless is a shared data contract: every function in every package returns the same structure, with the same column names, at the same geographic identifiers. Learn these patterns once and they work across the entire ecosystem.
Filtering by variable
bd <- get_business_dynamics(geography = "county", years = 2018:2023)
# Single variable
estabs <- bd |> filter(variable == "establishments")
# Multiple variables
rates <- bd |> filter(variable %in% c("estab_entry_rate", "estab_exit_rate"))
Pivoting to wide format
bd_wide <- get_business_dynamics(geography = "county", years = 2022:2023) |>
pivot_wider(names_from = variable, values_from = value)
# Now: geoid | year | establishments | estab_entries | estab_entry_rate | ...
Joining across packages
Because every package returns the same geoid + year identifiers, joining across packages is a simple left_join():
# Employment + population + business dynamics in one county profile
emp <- get_employment(geography = "county", years = 2023) |>
filter(variable == "employment") |>
select(geoid, employment = value)
pop <- get_population(geography = "county", years = 2023) |>
filter(variable == "population") |>
select(geoid, population = value)
estab <- get_business_dynamics(geography = "county", years = 2023) |>
filter(variable == "establishments") |>
select(geoid, establishments = value)
county_profile <- emp |>
left_join(pop, by = "geoid") |>
left_join(estab, by = "geoid") |>
mutate(
emp_per_capita = employment / population,
estab_per_capita = establishments / population
)
Summarizing by rural status
With a rural classification joined in, aggregating to rural/nonrural summaries is straightforward — and produces comparisons that are meaningful for rural research:
library(ruraldefinitions)
rural <- cbsa_2023 |> select(geoid, is_rural)
emp_summary <- get_employment(geography = "county", years = 2018:2023) |>
filter(variable == "employment") |>
left_join(rural, by = "geoid") |>
filter(!is.na(is_rural)) |>
group_by(year, is_rural) |>
summarize(
total_employment = sum(value, na.rm = TRUE),
n_counties = n_distinct(geoid),
.groups = "drop"
)
Visualizing with cori.charts
Tidy data maps directly to ggplot2 aesthetics — and cori.charts provides CORI-themed formatting:
library(ggplot2)
library(cori.charts)
load_fonts()
get_business_dynamics(geography = "nation", years = 2000:2023) |>
filter(variable %in% c("estab_entry_rate", "estab_exit_rate")) |>
ggplot(aes(x = year, y = value, color = variable)) +
geom_line(linewidth = 1.5) +
scale_color_cori(
palette = "ctg2buor",
labels = c("estab_entry_rate" = "Entry rate",
"estab_exit_rate" = "Exit rate")
) +
scale_y_continuous(
labels = scales::label_percent(accuracy = 0.1, scale = 1)
) +
theme_cori() +
labs(
title = "National establishment entry and exit rates, 2000–2023",
x = NULL,
y = NULL,
color = NULL,
caption = "Source: CORI analysis of Census Bureau Business Dynamics Statistics"
)
Related
Packages in this ecosystem: - cori.data.qcew — Employment & wages - cori.data.bds — Business dynamics - cori.data.pep — Population estimates - cori.data.fcc — Broadband coverage - ruraldefinitions — Rural classifications
Further reading: - Employment Rate vignette — cross-package analysis combining QCEW + PEP - Sector Analysis vignette — CORI super-sectors and rural economic composition - Weighted Averages vignette — why agg_var matters
NOTE Data in this ecosystem are curated from U.S. federal agency sources. This product uses the Census Bureau Data API but is not endorsed or certified by the Census Bureau. BLS.gov cannot vouch for data or analyses derived from these data after retrieval from BLS.gov.