GeoSlides
Market: United States
Browse templates
Home/ Guides/ FIPS Codes and GEOIDs: What the Numbers on a Map Mean

Map data·4 min read

FIPS Codes and GEOIDs: What the Numbers on a Map Mean

Every shape in a Census map carries a number, and that number is the only reliable way to attach your data to it. Here is how the digits are built at each level, what happens when you join on a name instead, and the one setting that quietly breaks the whole thing.

A county map of the United States drawn as separate outlined shapes in a warm neutral fill
Every shape here is identified by a five-digit code. The name is a label; the code is the address.

Two codes, and only one of them is stable

A shape in a Census boundary file carries two identifiers:

  • GEOID — the bare code: 13111 for Fannin County, Georgia.
  • GEOIDFQ — the fully qualified code: 0500000US13111. The first seven characters are the summary level, US is the nation, and the rest is the GEOID.

GEOIDFQ replaced an older field called AFFGEOID in the 2023 vintage. It exists because a bare 13111 does not say what kind of thing it is: the same string could be a county, a place, or a tract in a different file. The qualified form cannot be misread, which is why data.census.gov hands it out and why a join written against it survives a file swap.

FIPS is the older name for the same idea. The Federal Information Processing Standards published state and county codes from the 1970s until the standards were withdrawn in the 2000s; the Census Bureau kept using the numbers, so "FIPS code" survives in everyday use even though nothing is published under that name any more. A "FIPS county code" and a "county GEOID" are the same five digits.

What each digit group identifies

LevelGEOID lengthExampleReads as
State213Georgia
County513111State 13 + county 111
County subdivision101311109210County 13111 + subdivision 09210
Census tract1113111092100County 13111 + tract 092100
Block group12131110921001Tract + one digit
Place70653980State 06 + place 53980 (Orange, California)
Congressional district40603State 06 + district 03
ZIP Code Tabulation Area530214A ZCTA — not prefixed by state

Two of those rows cause most of the trouble in practice.

ZCTAs are not ZIP codes and are not state-scoped. A ZCTA is the Census Bureau's area approximation of a ZIP Code, drawn from addresses rather than from postal routes. The codes look alike, some are identical, and they do not nest inside counties the way a county nests inside a state.

Congressional districts are numbered per state, not nationally. 0603 is California's third district. There is no national district 603, and a file that sorts districts by GEOID will interleave all fifty states.

Why joining on a name fails

The obvious way to attach data to a map is to match on the place name. It works for states, because state names are unique. It fails at every level below that.

In the 2025 county file there are 3,235 features and only 1,927 distinct names. 443 county names are used in more than one place. Thirty-one counties are named Washington; twenty-six are named Jefferson, and twenty-six more are named Franklin. At place level it is worse: 32,629 places share 21,593 distinct names, and 17,466 of those names appear exactly once — so the majority of name joins are fine and the minority are silently wrong, which is the worst possible failure mode.

A county map of the United States in pale slate with white county boundaries
Thirty-one of these shapes are called Washington County. A spreadsheet with a name column and a value column cannot tell them apart; a spreadsheet with 31 rows of 53... can.

Concretely: a table of "Washington County" sales figures merged onto a county map on the name column will produce 31 candidate matches. Most tools either error out or, worse, take the first match and quietly paint the wrong state. Twenty-two places in the country are called Springfield. Thirty are called Fairview.

The fix is dull and total: join on the code, keep the name for the label only.

One worked example

Take 13111 and read it left to right:

  • 13 — Georgia, from the state FIPS list.
  • 111 — the county within Georgia. County codes run from 001 upward and are not contiguous; gaps are historical, not errors.

So 13111 is Fannin County. The qualified form, 0500000US13111, adds summary level 050 (state-county) and US, which is the Census Bureau's prefix for the nation. In a tract file the same county would appear as 13111092100 — the county code first, the tract code appended.

The join, done properly

Nine times out of ten, the bug is not the join itself but the column type. FIPS codes have leading zeros, and a CSV reader that infers types will turn 01 into 1, which then matches nothing except by accident.

import pandas as pd
import geopandas as gpd

# dtype=str is the whole fix. Without it, Alabama's state code
# becomes 1, and every Alabama county fails to match.
data = pd.read_csv("county_values.csv", dtype={"GEOID": str})
geo  = gpd.read_file("cb_2025_us_county_5m.geojson")

merged = geo.merge(data, on="GEOID", how="left", validate="one_to_one")
missing = merged["value"].isna().sum()
print(f"{missing} counties had no row in the table")

# Never join on NAME. It is a label: 443 county names repeat.

validate="one_to_one" is worth the keystroke. It turns a duplicated key into an exception rather than a row count that quietly doubles, which is how a map ends up with twice the population it should have.

If your data arrives with a state name and a county name and no codes at all, do not invent a join. The Census Bureau publishes a relationship file that maps every county name in every state to its GEOID, and the five-digit code is easier to build from STATEFP + COUNTYFP in any Census product than from a name match.

What the codes are not

  • Not ZIP codes. ZCTAs approximate them; they are not the same geography and they are not issued by the same agency.
  • Not stable across decades. County codes rarely change, but they do: Connecticut's county codes were retired when the planning regions arrived in 2022, and a tract code from 2010 will not point at the same tract in 2020.
  • Not a hierarchy you can assume. Independent cities in Virginia are county-level units with their own codes; a place can straddle a county line; a ZCTA can straddle a state line.

That last point is the one that catches people building a map for a slide. The geography has to match the data's unit of collection. If the sales report is by county and the map is by place, no amount of joining will make the numbers line up — the shapes are answering a different question.

Is a FIPS code the same as a GEOID?
For states and counties, yes — the five-digit county code is the same number either way. The Census Bureau now publishes it as GEOID, and the qualified form GEOIDFQ adds the summary level and country prefix.
How many digits is a county FIPS code?
Five: two for the state and three for the county within it. `13111` is Fannin County, Georgia.
Can I join Census data to a map using county names?
Not reliably. 443 county names appear more than once in the 2025 file, including 31 Washington Counties. Join on GEOID and use the name only as a label.
Why did my FIPS codes lose their leading zeros?
The CSV was read with type inference, so `01` became `1`. Read the column as a string and the join will work.

Shapes that already carry the code

Every county in our decks is a named shape with its Census GEOID attached, so a lookup table joins to the map without a name match anywhere.

See the county map

Questions

Is a FIPS code the same as a GEOID?
For states and counties, yes — the five-digit county code is the same number either way. The Census Bureau now publishes it as GEOID, and the qualified form GEOIDFQ adds the summary level and country prefix.
How many digits is a county FIPS code?
Five: two for the state and three for the county within it. `13111` is Fannin County, Georgia.
Can I join Census data to a map using county names?
Not reliably. 443 county names appear more than once in the 2025 file, including 31 Washington Counties. Join on GEOID and use the name only as a label.
Why did my FIPS codes lose their leading zeros?
The CSV was read with type inference, so `01` became `1`. Read the column as a string and the join will work.

Written in-house. Boundary counts are checked against the published files, and every figure on this page can be reproduced from the source named in it.

Keep reading