Live2026

NJ Parcel Flood Risk Dashboard

Flood exposure for all 3,478,722 New Jersey parcels, scored 0–100 and served with no backend.

  • flood
  • gis
  • data-pipeline
  • housing
  • python
  • javascript
  • 3,478,722Parcels scored statewide
  • 19.31%Parcels at risk
  • 25.86%Assessed value exposed
  • 1.89 hStatewide intersect, against a 12 h budget

Problem

New Jersey publishes everything you need in order to know whether a property sits in harm’s way — parcel geometry, MOD-IV tax assessments, FEMA’s flood hazard layer, NJDEP’s sea-level-rise projections, NFIP claims history. It publishes them as five unrelated datasets, at five different grains, none of which will join to another without work.

So the practical question — which parcels are exposed, how much value is behind them, and why does this one score what it scores — is answerable in principle and nobody’s job in practice. This dashboard is that join, done once, statewide, at parcel grain.

The dashboard's statewide view: a choropleth of New Jersey municipalities shaded by flood-risk score from none through severe, with a search box, filter controls, and a summary panel of parcel counts and assessed value.
Every parcel in New Jersey, scored and served from static files. The screening lens is deliberately a first-pass one — a due-diligence starting point, not a flood-zone determination.Source: nj-parcel-flood.pages.dev, statewide view.

Approach

Every parcel’s score is a weighted composite of three components, each normalised to the unit interval before weighting:

score = round(100 × (0.45·C_cur + 0.30·C_fut + 0.25·C_loss))
  • C_cur — overlap with FEMA’s Special Flood Hazard Area today, with a presence floor so a barely-touched parcel does not score misleadingly low.
  • C_fut — overlap with NJDEP’s projected future flood layers. Where that data does not cover a parcel it is estimated as half of C_cur and labelled as such — never presented as “no future risk.”
  • C_loss — the parcel’s census tract’s NFIP claims history, as a statewide percentile.

Scores sort into five bands, and every parcel’s detail panel shows the full breakdown. That “why is this number what it is” requirement drove the whole schema: a score a user cannot take apart is a score they should not trust.

A single parcel's detail panel in the dashboard, showing its overall flood-risk score alongside the separate current-flood, future-flood, and loss-history components that produce it, plus parcel attributes from the MOD-IV assessment record.
The score, taken apart. Each parcel carries its three drivers and its assessment record, so a screening result can be argued with rather than merely accepted.Source: nj-parcel-flood.pages.dev, parcel detail panel.
Technical detail — the precompute-everything architecture

There is no server and no runtime geoprocessing. The heavy work runs locally, partitioned by county and resumable, so a failure never restarts finished work:

  • Pipeline — Python with uv, DuckDB with its spatial extension, and GeoPandas: parcel core → flood-layer normalisation → statewide intersections → scoring → aggregates → PMTiles generation → search index → validation.
  • Tiles — tippecanoe in Docker producing PMTiles, served straight from object storage over HTTP range requests. No tile server runs anywhere.
  • App — Vite, React 18, TypeScript, Tailwind v4, MapLibre GL. Five views: search and map, jurisdiction summary, district exposure, ranked municipalities, methodology. Statewide address geocoding runs against New Jersey’s own government geocoder.
  • Hosting — Cloudflare Pages for the app, R2 for tiles, search shards, and summaries. Zero egress fees matter here: the map data alone is most of a gigabyte on every real session.

Two privacy rules are absolute. No owner names or mailing addresses appear in any published artifact. And NFIP loss evidence is aggregated to census tract, never to parcel — the redacted claims dataset does not support parcel-level precision, and pretending it does would be both wrong and a privacy failure.

Results

Run statewide, either lens, all property classes:

  • 671,829 of 3,478,722 parcels — 19.31% — are at risk.
  • 25.86% of assessed value is exposed.
Bar chart in the dashboard comparing exposure by property class, showing both the share of parcels at risk and the share of assessed value exposed for each class.
Exposure by property class, as both a parcel count and a value total — the two answer different questions and disagree sharply. 'Other' (rail, utility, miscellaneous) carries the highest at-risk share at 31.22% and by far the highest value exposure at 71.69%; residential sits lowest on both at 15.90% and 21.15%.Source: nj-parcel-flood.pages.dev, district exposure view.

That utility-and-infrastructure result is plausible rather than alarming: siting is often water-adjacent for practical reasons. Residential sitting lowest on both measures is consistent with its being the most widespread and least water-concentrated class statewide.

Ranked table of New Jersey municipalities in the dashboard, sorted by percentage of parcels at risk, with parcel counts and exposed assessed value alongside.
Municipalities ranked by share of parcels at risk. The ranking is the product: it turns a statewide surface into a prioritisation list someone can actually work down.Source: nj-parcel-flood.pages.dev, ranked municipalities view.

What the build cost, and what it got wrong

The heaviest stage — statewide parcel-to-flood intersections — completed in 1.89 hours against a 12-hour budget. That is the easy number to report. These are the others.

  • 6 of 7 publication gates pass. The seventh ships as a disclosed limitation. The statewide MOD-IV join rate lands at 88.34%, below the project’s own 97% target. It is logged and carried forward rather than papered over or quietly relaxed.
  • A rule that passed every targeted test and still broke real towns. Fixing a municipality name-matching gap, a general RIVER → RIV abbreviation rule looked correct against every synthetic test written for it — and quietly broke River Vale and River Edge, whose names fuse the word into one token (RIVERVALE). Caught by re-verifying against the full statewide dataset rather than trusting the test suite, then reverted to a narrow explicit override for the one town that needed it.
  • Deploying for real caught what dev testing could not. The production build silently failed to ship MapLibre’s own worker script. The first fix looked complete — file shipped, correct MIME type — but the worker still died on load, invisible to console-error checking. Found through Playwright’s worker-lifecycle API showing created then closed within milliseconds.
  • A shipped feature, reverted on UX grounds rather than technical ones. Widening the tileset so parcel mode could zoom out as far as municipality mode was a real, working, verified fix. It was reverted the same day anyway: at that zoom the view stopped reading as “the flood layer” the way the continuous municipality choropleth did. Correct code is not automatically the right product decision.

Automated accessibility and end-to-end testing (Playwright with axe-core) covers search, filter cascades, chart-versus-data consistency, and CSV export across 16 tests, with zero serious accessibility violations. Running the suite for real — not merely writing it — caught defects no amount of manual spot-checking surfaced, including an interactive button nested inside an ARIA option element.

Data sources

DatasetSource
Parcel geometry + MOD-IV attributesNJGIN/NJOGIS Parcels and MOD-IV Composite of NJ
Current flood hazardFEMA National Flood Hazard Layer
Future flood indicatorsNJDEP climate-adjusted / sea-level-rise layers
NFIP loss evidenceOpenFEMA FIMA NFIP Redacted Claims, tract-level
BoundariesCensus TIGER counties and municipalities
Address geocodingNew Jersey’s own ArcGIS geocoder (geo.nj.gov)

Screening tool — not a flood determination. Scores are relative screening indicators, not insurance ratings, legal flood-zone determinations, or property valuations.

Share this page

https://abdulkalam.pages.dev/projects/nj-parcel-flood-risk/

Scan to open this page. Download the SVG for print.