How to Find Scour-Critical Bridges Over Rivers

On this page

Problem statement

Most bridges that collapse in the United States are not brought down by traffic or age but by water: floods scour away the riverbed around piers and abutments until the foundation is undermined. The National Bridge Inventory records each bridge's vulnerability to scour in item 113, a single character from 0 to 9 plus N, U and T. This guide decodes it for the 2025 inventory, counts the bridges rated scour critical and those whose foundations are unknown, finds where they are and how much traffic they carry, and relates scour to condition.

Quick answer

Codes 0 to 3 of SCOUR_CRITICAL_113 mean scour critical: the foundation is, or could become, unstable under scour. N means the bridge is not over water; U means the foundation is unknown, so scour cannot be assessed. Count and map those, and keep U separate from both groups.

sc = nbi.SCOUR_CRITICAL_113.str.strip()
critical = sc.isin(["0", "1", "2", "3"])
water = sc != "N"
print(f"bridges over water (item 113 not N): {water.sum():,}; scour critical (codes 0-3): {critical.sum():,} ({critical[water].mean():.1%} of those over water)")
print("item 113 codes:", sc.value_counts().reindex(list("9876543210UTN")).fillna(0).astype(int).to_dict())
bridges over water (item 113 not N): 516,090; scour critical (codes 0-3): 19,775 (3.8% of those over water)
item 113 codes: {'9': 2457, '8': 318860, '7': 12576, '6': 3888, '5': 110059, '4': 24218, '3': 18949, '2': 685, '1': 56, '0': 85, 'U': 24250, 'T': 7, 'N': 108103}

Of 516,090 bridges over water (item 113 other than N), 19,775 are scour critical β€” 3.8%. Most bridges over water are rated stable (codes 8 and 5); 24,250 have unknown foundations (U).

Map of the lower 48 with scour-critical bridges in red and bridges with unknown foundations in grey Map of the lower 48 with scour-critical bridges in red and bridges with unknown foundations in grey
Scour-critical bridges and bridges with unknown foundations; Pennsylvania has the most critical ones (2,249).

Decoding item 113

1. What the codes mean

SCOUR = {"N": "not over water", "U": "unknown foundation", "T": "tidal, not evaluated", "9": "on dry land", "8": "stable, above footing",
         "7": "countermeasures installed", "6": "not yet evaluated", "5": "stable, within footing", "4": "stable, action needed",
         "3": "critical: unstable", "2": "critical: extensive scour", "1": "critical: failure imminent", "0": "failed, closed"}
t = sc.map(SCOUR).value_counts()
print(t.to_string())
SCOUR_CRITICAL_113
stable, above footing         318860
stable, within footing        110059
not over water                108103
unknown foundation             24250
stable, action needed          24218
critical: unstable             18949
countermeasures installed      12576
not yet evaluated               3888
on dry land                     2457
critical: extensive scour        685
failed, closed                    85
critical: failure imminent        56
tidal, not evaluated               7

The codes run from 9 (on dry land, above flood water) through 8 (stable, foundations above the scour depth) and 5 (stable, scour within the footing) to 3 (unstable for assessed scour), 2 (extensive scour has occurred), 1 (failure imminent) and 0 (failed and closed). Code 7 means countermeasures β€” riprap, sheet piling β€” have been installed after a problem was found; 12,576 bridges have them.

2. Unknown foundations

print(f"unknown foundations (U): {(sc == 'U').sum():,}; not yet evaluated (6): {(sc == '6').sum():,}")
print(f"daily crossings on scour-critical bridges: {nbi.loc[critical, 'adt'].sum() / 1e6:,.1f} million; on unknown-foundation bridges: {nbi.loc[sc == 'U', 'adt'].sum() / 1e6:,.1f} million")
unknown foundations (U): 24,250; not yet evaluated (6): 3,888
daily crossings on scour-critical bridges: 76.4 million; on unknown-foundation bridges: 36.9 million

24,250 bridges have foundations nobody can document β€” usually older bridges whose plans are lost β€” and 3,888 are over water but not yet evaluated. Scour-critical bridges carry 76.4 million vehicle crossings a day and unknown-foundation bridges another 36.9 million.

3. Where they are

st = critical.groupby(nbi.state).sum().sort_values(ascending=False)
print("scour-critical bridges by state, most:", st.head(6).to_dict())
share = critical.groupby(nbi.state).sum() / water.groupby(nbi.state).sum()
print("share of a state's water crossings that are critical, highest:", share.sort_values(ascending=False).head(5).round(3).to_dict())
scour-critical bridges by state, most: {'PA': 2249, 'LA': 1302, 'OR': 1225, 'SC': 1217, 'MI': 1077, 'NE': 986}
share of a state's water crossings that are critical, highest: {'PR': 0.271, 'RI': 0.249, 'OR': 0.172, 'SC': 0.15, 'MI': 0.129}

Pennsylvania has the most scour-critical bridges (2,249), then Louisiana, Oregon, South Carolina and Michigan. As a share of water crossings, Puerto Rico (27.1%) and Rhode Island (24.9%) lead, with Oregon at 17.2%. Rating practice differs between states β€” how conservatively each assesses scour β€” as well as rivers and geology.

Horizontal bars on a log scale of bridges by scour code, from failed through critical and stable to unknown Horizontal bars on a log scale of bridges by scour code, from failed through critical and stable to unknown
Of 516,090 bridges over water, 19,775 are scour critical and 24,250 have unknown foundations.

4. Critical and poor

print(pd.crosstab(critical, nbi.cond, normalize="index").round(3).rename(index={True: "scour critical", False: "not critical"}).to_string())
cond                    F      G      P
SCOUR_CRITICAL_113                     
not critical        0.492  0.447  0.060
scour critical      0.610  0.124  0.266

Scour-critical bridges are far more often poor: 26.6% against 6.0% of other bridges, and only 12.4% are good. Scour damage shows up in the substructure rating, which then sets the bridge's condition.

What they cross, and the failed ones

The data used on this page

The Federal Highway Administration's National Bridge Inventory for 2025, the scour-critical item, coded as in FHWA's Recording and Coding Guide, and Census Bureau 2023 states.

import zipfile
from pathlib import Path

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

Path("data").mkdir(exist_ok=True)
# FHWA National Bridge Inventory, 2025 submission, highway bridges, all states in one comma-delimited file (53 MB zip).
# The server is slow and drops long downloads, so resume until the file is complete.
URL = "https://www.fhwa.dot.gov/bridge/nbi/2025hwybronefiledel.zip"
f = Path("data/2025hwybronefiledel.zip")
size = int(requests.head(URL, allow_redirects=True, timeout=60).headers["Content-Length"])
while not f.exists() or f.stat().st_size < size:
    have = f.stat().st_size if f.exists() else 0
    try:
        with requests.get(URL, headers={"Range": f"bytes={have}-"}, stream=True, timeout=120) as r, open(f, "ab") as out:
            for chunk in r.iter_content(1 << 20):
                out.write(chunk)
    except requests.RequestException:
        pass                                                   # resume from what arrived
with zipfile.ZipFile(f) as z:
    nbi = pd.read_csv(z.open("2025HwyBridgesDelimitedAllStates.txt"), quotechar="'", dtype=str, low_memory=False)


def dms(s, west=False):
    """NBI packs coordinates as DDMMSSss (latitude) and DDDMMSSss (longitude, positive west)."""
    s = s.str.strip().str.zfill(9 if west else 8)
    d = s.str[:-6].astype(float) + s.str[-6:-4].astype(float) / 60 + s.str[-4:].astype(float) / 100 / 3600
    return -d if west else d


nbi["lat"], nbi["lon"] = dms(nbi.LAT_016), dms(nbi.LONG_017, west=True)
nbi["cond"] = nbi.BRIDGE_CONDITION                                   # G, F or P, derived by FHWA
nbi["adt"] = pd.to_numeric(nbi.ADT_029, errors="coerce")
nbi["built"] = pd.to_numeric(nbi.YEAR_BUILT_027, errors="coerce")
nbi["area"] = pd.to_numeric(nbi.DECK_AREA, errors="coerce")
for name in ["cb_2023_us_state_20m.zip"]:
    if not Path(f"data/{name}").exists():
        Path(f"data/{name}").write_bytes(requests.get(f"https://www2.census.gov/geo/tiger/GENZ2023/shp/{name}", timeout=300).content)
states = gpd.read_file("data/cb_2023_us_state_20m.zip").to_crs(4326)
nbi["state"] = nbi.STATE_CODE_001.map(states.set_index("STATEFP").STUSPS)
print(f"{len(nbi):,} highway bridges, {nbi.shape[1]} fields, {nbi.STATE_CODE_001.nunique()} state codes")
624,193 highway bridges, 130 fields, 53 state codes

Example 1: what crosses over

und = nbi.SERVICE_UND_042B.str.strip()
UND = {"5": "waterway", "6": "highway and waterway", "7": "railroad and waterway", "8": "highway, waterway and railroad", "9": "relief for waterway"}
print("scour-critical bridges by what they cross:", und[critical].map(UND).fillna("other").value_counts().to_dict())
scour-critical bridges by what they cross: {'waterway': 19329, 'relief for waterway': 190, 'highway and waterway': 145, 'railroad and waterway': 61, 'highway, waterway and railroad': 45, 'other': 5}

Almost all scour-critical bridges cross a waterway alone (19,329); a few also cross a road or railway, and 190 are relief bridges that carry a road over floodplain only in high water.

Stacked bars comparing condition of scour-critical and other bridges, with far more poor bridges among the critical ones Stacked bars comparing condition of scour-critical and other bridges, with far more poor bridges among the critical ones
26.6% of scour-critical bridges are poor, against 6.0% of others.

Example 2: the failed ones

f0 = nbi[sc == "0"]
print(f"code 0 (bridge failed, closed): {len(f0)}; status 'K' closed among them: {(f0.OPEN_CLOSED_POSTED_041 == 'K').mean():.0%}")
code 0 (bridge failed, closed): 85; status 'K' closed among them: 71%

85 bridges are coded 0, failed. 71% of them have status K, closed; the rest are coded otherwise in item 41, a reminder to cross-check one coded field against another before trusting either.

Why scour is its own rating

Scour is the leading cause of bridge failure in the United States, and it happens out of sight: during a flood the riverbed around a pier can drop several metres and refill afterwards, so a routine inspection at low water sees nothing. FHWA therefore asks for a separate engineering assessment of each bridge over water, and item 113 records the result. A scour-critical bridge must have a plan of action β€” monitoring during floods, closure triggers, countermeasures.

Scour-critical does not mean the bridge is unsafe today; it means its foundation could become unstable in a large enough flood. Combining item 113 with a flood hazard layer β€” which bridges are critical and also in a floodplain or on a river with rising peak flows β€” is the natural next step for a risk map.

Pitfalls with item 113

  • Strip the code. Codes may carry spaces; .str.strip() first.
  • U is not stable. Unknown foundations are a separate risk class; do not fold them into "not critical".
  • T (tidal) is rare and means not evaluated in a tidal waterway.
  • The new specification (SNBI) replaces item 113 with different fields; future files will need a crosswalk.

FAQ

How many US bridges are scour critical?

19,775 in the 2025 National Bridge Inventory, 3.8% of bridges over water; another 24,250 have unknown foundations.

What does scour critical mean?

That the bridge's foundation is, or could become, unstable from erosion of the riverbed during floods (item 113 codes 0 to 3).