How to Count US Dams by Purpose and Owner

On this page

Problem statement

Ask what America's dams are for and the answer depends on how you count. By number, most are small private dams for recreation, farm ponds and fire protection. By storage, a few hundred federal dams for flood control, hydropower and irrigation dominate. The National Inventory of Dams records a primary purpose, an owner type and a list of all purposes for each dam, separated by semicolons, so a dam that serves three purposes is counted once by its primary purpose and three times by its list. This page counts dams by purpose and owner, by number and by storage.

Quick answer

Count the primary purpose by number and by storage, side by side:

one = nid.sort_values("isAssociatedStructureId").drop_duplicates("nidId")
one = one[one.name != "Soo Locks"]
t = one.groupby("primaryPurposeId").agg(dams=("nidId", "size"), storage_maf=("nidStorage", lambda s: s.sum() / 1e6))
t["dam_share"], t["storage_share"] = t.dams / t.dams.sum(), t.storage_maf / t.storage_maf.sum()
print(t.sort_values("dams", ascending=False).round(3).to_string())
                                             dams  storage_maf  dam_share  storage_share
primaryPurposeId                                                                        
Recreation                                  30901       37.511      0.359          0.044
Flood Risk Reduction                        14968      424.517      0.174          0.497
Fire Protection, Stock, Or Small Fish Pond  11997        1.723      0.139          0.002
Irrigation                                   7620       38.764      0.089          0.045
Other                                        7443       17.526      0.086          0.021
Water Supply                                 5162       53.845      0.060          0.063
Fish and Wildlife Pond                       3175        8.967      0.037          0.011
Hydroelectric                                1755      224.972      0.020          0.263
Tailings                                     1160       11.199      0.013          0.013
Grade Stabilization                           964        0.150      0.011          0.000
Debris Control                                679        0.531      0.008          0.001
Navigation                                    225       34.205      0.003          0.040

By number, recreation dams are 35.9% of the inventory and stock and fish ponds another 13.9%, but together they hold under 5% of the storage. Flood risk reduction is 17.4% of dams and 49.7% of storage, and hydroelectric dams are 2.0% of dams but 26.3% of storage. The same table gives opposite answers to "what are dams for" depending on the column you read.

Paired bars of share of dams and share of storage by primary purpose: recreation 36% of dams but 4% of storage, flood risk reduction 17% and 50%, hydroelectric 2% and 26%. Paired bars of share of dams and share of storage by primary purpose: recreation 36% of dams but 4% of storage, flood risk reduction 17% and 50%, hydroelectric 2% and 26%.
Purposes by number of dams and by storage.

Primary purpose and all purposes

1. Splitting the purpose list

p = one.purposeIds.str.split(";").explode().str.strip()
print(f"dams with more than one purpose: {(one.purposeIds.str.count(';') > 0).sum():,}")
print(p.value_counts().head(8).to_string())
dams with more than one purpose: 17,286
purposeIds
Recreation                                    38371
Flood Risk Reduction                          17608
Fire Protection, Stock, Or Small Fish Pond    15712
Irrigation                                     9416
Other                                          9064
Water Supply                                   7154
Fish and Wildlife Pond                         5486
Hydroelectric                                  2102

17,286 dams list more than one purpose. Counted by every purpose they serve, recreation appears on 38,371 dams, compared with 30,901 as a primary purpose, and flood risk reduction on 17,608. A count over the exploded list totals more than the number of dams, so present it as "dams serving each purpose", never as shares that add to 100%.

2. Owners

o = one.groupby("primaryOwnerTypeId").agg(dams=("nidId", "size"), storage_maf=("nidStorage", lambda s: s.sum() / 1e6), high=("publicHazardId", lambda s: (s == "High").sum()))
print(o.sort_values("dams", ascending=False).round(1).to_string())
                     dams  storage_maf  high
primaryOwnerTypeId                          
Private             60172         69.4  7432
Local Government    18620         82.0  5398
State                6705         58.9  1570
Federal              3188        586.5  1071
Not Listed           1617          6.5   199
Public Utility       1510         55.8   804
Tribal Government      17          0.0     0

Private owners hold 60,172 dams but only 69.4 million acre-feet of storage. The federal government owns 3,188 dams with 586.5 million, more than everyone else combined, although that total includes the Soo Locks' Great Lake figure and repeated dike segments. Private owners also hold the most high-hazard dams, 7,432.

Paired bars by owner type: private owners hold about two thirds of dams but under a tenth of storage, federal owners a few per cent of dams and over two thirds of storage. Paired bars by owner type: private owners hold about two thirds of dams but under a tenth of storage, federal owners a few per cent of dams and over two thirds of storage.
Owners by number of dams and by storage.

3. Who owns what

print(pd.crosstab(one.primaryPurposeId, one.primaryOwnerTypeId, normalize="index").loc[["Recreation", "Flood Risk Reduction", "Hydroelectric", "Irrigation", "Water Supply"], ["Private", "Local Government", "State", "Federal", "Public Utility"]].round(2).to_string())
primaryOwnerTypeId    Private  Local Government  State  Federal  Public Utility
primaryPurposeId                                                               
Recreation               0.78              0.10   0.08     0.02            0.00
Flood Risk Reduction     0.17              0.59   0.18     0.05            0.00
Hydroelectric            0.47              0.12   0.04     0.04            0.25
Irrigation               0.87              0.05   0.02     0.04            0.01
Water Supply             0.39              0.44   0.04     0.03            0.08

Recreation and irrigation dams are overwhelmingly private, flood-control dams mostly local government, and water-supply dams split between towns and private companies. A quarter of hydroelectric dams belong to public utilities and nearly half to private companies.

Dam types and federal agencies

The data used on this page

The US Army Corps of Engineers' National Inventory of Dams (NID), the whole inventory as a GeoPackage from its API, downloaded on 19 October 2026 and saved on this site, because the inventory is updated as states and agencies send revisions. Heights are in feet, storage in acre-feet and areas in acres, as the NID gives them.

from pathlib import Path
import zipfile

import geopandas as gpd
import numpy as np
import pandas as pd
import requests

Path("data").mkdir(exist_ok=True)
# US Army Corps of Engineers, National Inventory of Dams: the whole inventory as a GeoPackage, and the Census
# Bureau's 2024 cartographic boundary counties. Saved 19 October 2026, because the inventory is updated continuously.
# Live: https://nid.sec.usace.army.mil/api/nation/gpkg
ARCHIVE = "usace-nid-2026-10-19.zip"
if not Path(f"data/{ARCHIVE}").exists():
    Path(f"data/{ARCHIVE}").write_bytes(requests.get(f"https://data.spatialworkflow.io/{ARCHIVE}", timeout=900).content)
Z = zipfile.ZipFile(f"data/{ARCHIVE}")
if not Path("data/nid.gpkg").exists():
    Z.extract("nid.gpkg", "data")
NUMERIC = ["damHeight", "hydraulicHeight", "structuralHeight", "nidHeight", "damLength", "volume", "yearCompleted",
           "nidStorage", "maxStorage", "normalStorage", "surfaceArea", "drainageArea", "maxDischarge"]
nid = gpd.read_file("data/nid.gpkg")
nid[NUMERIC] = nid[NUMERIC].apply(pd.to_numeric, errors="coerce")       # the GeoPackage stores them as text
print(f"National Inventory of Dams: {len(nid):,} rows, {nid.nidId.nunique():,} NID ids")
National Inventory of Dams: 92,626 rows, 91,840 NID ids

Example 1: what dams are made of

print(one.primaryDamTypeId.value_counts(dropna=False).head(6).to_string())
primaryDamTypeId
Earth       77154
NaN          7774
Concrete     2287
Gravity      2141
Rockfill      792
Other         610

77,154 dams are earthfill, 84% of the dams counted once each: embankments of compacted soil, cheap and easy to build on small streams. Concrete, gravity and rockfill dams are a few thousand between them. 7,774 have no type recorded.

Horizontal bars on a log scale of dam types: 77,154 earth, 7,774 not recorded, then concrete, gravity, rockfill and smaller types. Horizontal bars on a log scale of dam types: 77,154 earth, 7,774 not recorded, then concrete, gravity, rockfill and smaller types.
What the dams are made of.

Example 2: federal owners

print(one.fedOwnerIds.str.split(";").explode().str.strip().value_counts().head(6).to_string())
fedOwnerIds
US Army Corps of Engineers    571
Forest Service                444
Bureau of Land Management     417
Bureau of Reclamation         337
US Army                       228
Fish and Wildlife Service     219

Among federal owners, the US Army Corps of Engineers owns the most dams, 571, followed by the Forest Service, the Bureau of Land Management and the Bureau of Reclamation.