Why are the longitude values negative?

Because the United States is in the western hemisphere. Geographic coordinates follow a standard sign convention: latitudes north of the equator are positive, and longitudes west of the prime meridian are negative. Every location in the U.S. therefore has a negative longitude:

geocode_zip("90210")
#> # A tibble: 1 × 3
#>   zipcode   lat   lng
#>   <chr>   <dbl> <dbl>
#> 1 90210    34.1 -118.

This is not an error, and you should not multiply lng by -1: mapping libraries, spatial packages, and web APIs all expect this convention.

Why is a valid ZIP code missing from zip_code_db?

Two common reasons:

  1. Data vintage. The bundled database is the frozen 0.3.5 snapshot, so ZIP codes introduced after its date are intentionally absent. For new analyses, choose a modern bundle and use reverse_zipcode_ng() or another _ng function. Check zip_data_version() (or zip_data_version(bundle)) to identify the selected contract.
  2. ZIP codes are not ZCTAs. USPS ZIP codes are collections of delivery routes and points, not areas. The Census Bureau’s ZIP Code Tabulation Areas (ZCTAs) approximate most — but not all — ZIP codes. Some USPS-only codes (typically P.O. Box or single-building “unique” codes, such as 91230 in Glendale, CA) have no ZCTA and no Census-derived attributes, and may be missing from ZCTA-oriented sources. Use is_zcta() to check whether a given ZIP code is also a ZCTA.

Relatedly, about 20% of the ZIP codes in zip_code_db (P.O. Box and unique codes) have no lat/lng coordinates; functions such as zip_distance() return NA distances for them.

How accurate is the city / county (“jurisdiction”) information?

Treat it as approximate. A ZIP code is a postal-delivery construct, not a municipal boundary: one ZIP code can cross city, county, and even state lines, and the USPS “city” name is the preferred mailing name, which frequently differs from the municipality a given address actually lies in (addresses just outside a city’s limits often carry that city’s name). The county column reflects the predominant county for the ZIP code. If you need authoritative jurisdiction assignment, geocode the full street address against boundary files (e.g., Census TIGER/Line) rather than relying on the ZIP code alone.

I get object 'zip_code_db' not found

The datasets are lazy-loaded with the package. This error almost always indicates a broken or partial installation — for example, a package library that was migrated between R versions. Reinstalling usually fixes it:

install.packages("zipcodeR")

If you want the data without attaching the package, use zipcodeR::zip_code_db.

How do I get county FIPS codes from a ZIP code?

For a new analysis, use reverse_zipcode_ng() with an explicitly selected bundle. Its output includes state_fips (two digits) and county_fips (the full five-digit county identifier) for the predominant county recorded for the ZIP-level row. Remember that a ZIP can cross county boundaries; this is not a point-level jurisdiction assignment.

The unsuffixed reverse_zipcode() keeps its historical 0.3.5 column schema so an existing script is not changed by a package upgrade.

Why does zipcodeR still install raster and tidycensus?

They remain installation dependencies because some historical functions need them to reproduce exact 0.3.5 results. They are no longer loaded by library(zipcodeR): a legacy function loads the needed namespace only when it is called, while the recommended _ng functions avoid those paths. This keeps package startup isolated from the former raster/terra and GDAL/Arrow load failures without changing an old distance calculation.

Where does the data come from?

zip_code_db derives from the uszipcode project’s database, which aggregates U.S. Census Bureau data (decennial census, ACS, gazetteer files) with USPS-derived ZIP code attributes. The three bundled datasets are the exact snapshots distributed by zipcodeR 0.3.5: the 2021 uszipcode-derived ZIP database, the Census 2010 ZCTA-to-tract relationship, and the pre-2020 HUD-USPS ZIP-to-district relationship. They are intentionally frozen so a legacy call cannot be retconned by a package upgrade. zip_data_version() reports this contract.

Newer Census relationships and refreshed attributes are distributed as separate, checksum-pinned data bundles. They are used only when a bundle is passed explicitly to an _ng function. The bundle’s manifest and reproducibility archive contain the source vintages, raw source hashes, licenses, pipeline commit, dependency lock, validation report, and quality sidecars. No USPS-only ZIP receives a city-derived proxy centroid or a city-wide inferred congressional district.

Which API should a new project use?

Use _ng functions with a named data bundle for new analyses. This is the forward-looking interface and makes the choice of newer data visible in the R code. It does not silently track future releases: keep the exact version and SHA recorded with the project. Keep using unsuffixed functions for existing scripts or when reproducing historical zipcodeR results.