About
Addresses not validated at collection are often inconsistently formatted and standardized, making them difficult to compare or link to other address data. The goal of addr is to clean, parse, standardize, match, and geocode real-world, noisy US addresses in R.
addr can parse address components from strings and build vctrs-based address vectors, including addr() vectors and the addr_number(), addr_street(), and addr_place() component vectors. Each are structured to reuse the United States Thoroughfare, Landmark, and Postal Address Data Standard from the US Federal Geographic Data Committee. Every component stored in these typed vectors is canonicalized to uppercase, making it visually distinct from raw input text and directly comparable without additional case handling.

The standard also facilitates efficient operations with the Department of Transportation’s National Address Database for address matching and with the Census TIGER/Line Shapefiles for street-range geocoding. Address vectors can be standardized, matched, joined, and used as data-frame columns, allowing standard R tools to work with nested address structures.
Installation
Install the latest stable release of addr from R-universe with:
install.packages("addr", repos = c("https://geomarker-io.r-universe.dev", "https://cloud.r-project.org"))Or, install the development version of addr from GitHub with:
# install.packages("pak")
pak::pak("geomarker-io/addr")Installing addr from GitHub requires a working Rust toolchain; install one using rustup.
Getting started
addr vectors
addr vectors behave like standard R vectors: they recycle, subset, and combine with vctrs tooling. You can parse text into an addr vector with as_addr() or build one from component vectors with addr().
as_addr(c("3333 Burnet Ave Cincinnati OH 45229",
"5130 Rapid Run Rd Cincinnati OH 45238"))
#> <addr>
#> @ number: <addr_number> function ()
#> .. @ prefix: chr [1:2] "" ""
#> .. @ digits: chr [1:2] "3333" "5130"
#> .. @ suffix: chr [1:2] "" ""
#> @ street: <addr_street> function ()
#> .. @ predirectional : chr [1:2] "" ""
#> .. @ premodifier : chr [1:2] "" ""
#> .. @ pretype : chr [1:2] "" ""
#> .. @ name : chr [1:2] "BURNET" "RAPID RUN"
#> .. @ posttype : chr [1:2] "AVE" "RD"
#> .. @ postdirectional: chr [1:2] "" ""
#> @ place : <addr_place> function ()
#> .. @ name : chr [1:2] "CINCINNATI" "CINCINNATI"
#> .. @ state : chr [1:2] "OH" "OH"
#> .. @ zipcode: chr [1:2] "45229" "45238"Address Matching
addr_match() compares one addr vector to another and returns one selected reference address for each input address. Matching is staged: ZIP codes are matched first, then streets are matched within each matched ZIP code, then address numbers are matched within each matched ZIP/street group. This keeps matching fast while still allowing common street-name, phonetic, ZIP-code, and address-number variation.
Use addr_left_join() when the goal is to join data frames with addr columns. It uses the same staged matching as addr_match() and then expands exact duplicate reference rows when more than one row in y has the selected address. Use addr_fuzzy_left_join() when you need all fuzzy candidate matches rather than one selected match.
For repeated matching against the same reference addresses, prepare the reference once with addr_match_prepare() and reuse the returned index in later addr_match() or addr_left_join() calls.
National Address Database
nad() reads county-level address points from the U.S. Department of Transportation National Address Database, including reconstruction of addr and s2 columns. Counties can be requested by county name plus state, such as "Hamilton", "OH", or by 5-digit county FIPS code, such as "39061". On first use, nad_download() installs USDOT’s compressed NAD revision 23 flat-file archive as a durable managed local copy using stow(). The nationwide NAD source is large and county extraction requires a complete streaming scan, so addr caches each processed county under v2/nad/23 in its package-specific user data directory. nad_catalog() reads the packaged revision 23 catalog of 2,259 source-available counties and their source row counts; nad_install() checks this catalog before scanning the national source. NAD23 has no county FIPS field, so the catalog retains each exact source label and maps it to the package’s Census county reference, including separate unsuffixed county and explicit independent-city labels.
Processed counties form a Hive-partitioned Parquet dataset; use nad_dataset() to open all installed counties as one lazy Arrow dataset and filter or project the primitive address columns before collecting them:
nad_dataset() |>
dplyr::filter(state == "OH", county_fips == "39017") |>
dplyr::select(uuid, address_number, street_name, longitude, latitude) |>
dplyr::collect()Geocoding
Matched NAD coordinates can be used as a geocode, but placement often varies by the contributing organization and state. If linking to parcel geographies, intersection with parcel boundaries or their centroids can be used. Street range geocoding does not use address-level data, but instead interpolates the location with possible street ranges provided by census.gov.
In any case, geocoding includes (1) cleaning address text, (2) tagging the address, (3) harmonizing the address tags, (4) matching the ZIP code and street combinations. Any differences between the methods arise when placing a coordinate after matching the ZIP code and street

geocode() converts addr() vectors to point locations using Census TIGER address ranges. It matches the input street to installed TIGER address features, chooses the best address range and street side from the address number, interpolates a point along the range, and offsets that point from the street line. Geocoding returns the input address, matched ZIP code, matched street, point s2 geography, and s2 cell. Inputs with missing or unmatched ZIP codes, streets, or address ranges return missing geographies rather than centroids of larger areas.
TIGER Address Features
TIGER address features are Census street-segment address ranges. addr stores them as a hive-partitioned, multi-file parquet dataset, grouped by ZIP-code partitions and county files, so geocoding can read only the local files needed for the input ZIP codes. Read TIGER address features for one or more ZIP codes with taf(), but geocode() automatically installs all county files that may contain the ZIP codes in an input address vector as needed. Like with the NAD dataset, use taf_dataset() to open the installed multi-file dataset with arrow for advanced lazy dataset queries.
Each missing county requires two Census downloads, one FEATNAMES ZIP and one ADDRFEAT ZIP. addr sends actual HTTPS requests at least one second apart and retries transient failures three times with increasing delays. Successfully downloaded source ZIPs remain in the managed cache, so rerun the same call with redownload = FALSE after a failure to resume rather than start over.
Census does not publish a numeric TIGER request limit. Plan downloads by the number of unique missing counties, not the number of input ZIP codes: a ZIP can cross county lines, and place or typographical ZIP variants can expand the county set substantially. In the packaged 2025 catalog, one exact ZIP needs a median of one county and 95% need no more than three; with typographical variants enabled, the median is seven and 95% need no more than 15. Place and county-subdivision variants can produce larger outliers, so no ZIP-count limit is reliable when variants are enabled.
As a conservative addr guideline, on-demand HTTPS installation is intended for at most 10 missing counties (at most 20 source requests) in one job. Preview the exact number without downloading anything:
needed <- taf_needed_counties(
x,
year = "2025",
zip_variants = TRUE,
place_zip_variants = TRUE
)
installed <- unique(taf_manifest("2025")$county_fips)
length(setdiff(unique(needed$county_fips), installed))For more than 10 missing counties, install the 2025 TAF fuel bundle below. Setting place_zip_variants = FALSE and zip_variants = FALSE can reduce downloads when the broader matching search is not needed.
For bulk development work when the bundle is not suitable, Census recommends an anonymous FTP client for a large number of TIGER files. FTP is unencrypted, so addr never switches to it automatically. Select it explicitly for the current R session, then restore HTTPS afterward:
options(addr.tiger_download_protocol = "ftp")
# taf_install(...) or taf_ensure(...)
options(addr.tiger_download_protocol = "https")An invalid HTML Request Rejected response is never cached as a TIGER ZIP. If all retries fail, the error identifies the rejection and includes the Census support ID when the response provides one.
TAF fuel bundle
The addr 2.0.0 GitHub release provides a schema-v2 national 2025 TIGER Address Features fuel bundle for users who prefer one large download instead of installing county data as needed. The bundle contains the processed county-ZIP dataset and its manifest but not the stow-managed TIGER source ZIP files. It requires addr 2.0.0 and the bash, tar, zstd, and shasum command-line tools.
Download the archive and its JSON sidecar from the release:
curl --fail --location --remote-name \
https://github.com/geomarker-io/addr/releases/download/v2.0.0/addr-taf-v2-2025.tar.zst
curl --fail --location --remote-name \
https://github.com/geomarker-io/addr/releases/download/v2.0.0/addr-taf-v2-2025.jsonRun the installer from a shell:
bash "$(Rscript -e 'cat(system.file("exec", "install-addr-taf-fuel.sh", package = "addr"))')" \
addr-taf-v2-2025.tar.zstThe installer reads the adjacent JSON sidecar, verifies the archive’s SHA-256 digest, confirms exact package compatibility and expected paths and file counts, and validates the staged county_zip.parquet manifest and every inventoried county-ZIP Parquet file. It then restores runtime-optimized Snappy Parquet files before moving either directory. The download is about 1.4 GiB and installation requires several additional gigabytes of temporary and destination disk space.
By default, files are installed beneath the directory returned by:
The installed data and manifest paths are:
v2/tiger_addr_feat/2025
v2/tiger_addr_feat_manifest/2025
Set R_USER_DATA_DIR before installation to use another storage location, such as scratch space on a cluster:
export R_USER_DATA_DIR=/scratch/<user>/addr-data
bash "$(Rscript -e 'cat(system.file("exec", "install-addr-taf-fuel.sh", package = "addr"))')" \
addr-taf-v2-2025.tar.zstThe installer refuses to overwrite either existing year-specific directory. Remove both directories before deliberately replacing an installation, or set R_USER_DATA_DIR to install in a different location.
Maintainers create the archive and sidecar with the same one-shot development workflow that rebuilds every county file and regenerates the packaged catalog:
The release assets are written to the current directory by default. Set ADDR_TAF_RELEASE_DIR to choose another output directory. The sidecar records the schema, exact required addr version, TAF dataset version and year, archive and installed Parquet codecs, archive size and SHA-256 digest, installed paths, manifest row count, and expected file counts.
Container and command-line interface
An OCI-compatible runtime image with R and addr installed is published to the GitHub Container Registry:
Container release tags mirror addr package release versions. For reproducible work, use a specific release such as ghcr.io/geomarker-io/addr:v2.0.0.
The image does not include or pre-install TIGER/Line or National Address Database data. Runtime data uses the standard addr user data directory under /opt/addr-data/R/addr. Mount /opt/addr-data when you want downloads or derived data to persist across runs:
Batch geocoding on a cluster
The container includes an addr-geocode command for CSV or parquet files with a column named exactly address. The command writes a deterministic output file next to the input, matching the input file type and appending TIGER range geocoding columns. The filename records both the installed addr version and selected preset; for example, strict geocoding of addresses.csv with addr 2.0.0 writes addresses__addr-v2.0.0__preset-strict__geocoded.csv. Geocoding uses the installed geocode() defaults, including its default TIGER year. Use --preset to select one of four matching strategies:
| Preset | Behavior |
|---|---|
default |
Use all geocode() defaults. |
strict |
Search only the input ZIP and set both street-name distances to zero. |
exact-zip |
Search only the input ZIP with default street matching. |
loose |
Set fuzzy street-name distance to three and ignore street type and directionals, favoring recall over precision. |
See the geocode() reference for the underlying arguments and defaults. On systems that use Apptainer, pull a release-tagged image and bind user-specific scratch directories for persistent addr data and temporary files:
apptainer pull addr_v2.0.0.sif docker://ghcr.io/geomarker-io/addr:v2.0.0
mkdir -p /scratch/<cchmc-user>/addr-data /scratch/<cchmc-user>/addr-tmp
apptainer exec --cleanenv --contain \
--bind /scratch/<cchmc-user>/addr-data:/opt/addr-data \
--bind /scratch/<cchmc-user>/addr-tmp:/tmp \
--bind "$PWD:/work" \
addr_v2.0.0.sif \
addr-geocode \
--input /work/addresses.csv \
--preset strictFor example, Cole’s CCHMC username is broeg1, so his scratch directories use /scratch/broeg1/:
Use --cleanenv and --contain so the container does not inherit host R environment variables, home-directory data, or temporary directories.
For local R installations, run the installed script from the shell:
Rscript "$(Rscript -e 'cat(system.file("exec", "addr-geocode", package = "addr"))')" \
--input addresses.csvYou can also create a one-time shell symlink:
mkdir -p "$HOME/.local/bin"
ln -s "$(Rscript -e 'cat(system.file("exec", "addr-geocode", package = "addr"))')" \
"$HOME/.local/bin/addr-geocode"Then run:
For local image development, use just build, just run, and just test-container with the container CLI. The just run target resolves tools::R_user_dir("addr", "data") with the local R installation and mounts that directory into the container when it already exists.