For a side project I needed something that turned out to be weirdly hard to find: a free, clean list of the world's seaports — real depths, coordinates, and the codes ships actually use. Everything out there was paywalled, login-walled, or a table that looked untouched since 2005.
So I built the thing I wanted. Then it grew: The Port Index — 3,804 seaports and 9,640 airports, free, no signup, and the whole dataset downloadable as CSV/JSON. Here's what I learned building it.
The data is all public domain — you just have to find it
No scraping, no licensing fees. Three public-domain sources do the heavy lifting:
- NGA World Port Index (Pub 150) — a U.S. government dataset of ~4,000 ports, each with 100+ coded attributes (depths, max vessel size, pilotage, facilities…).
- UN/LOCODE — the UNECE location codes.
- OurAirports — a public-domain database behind the 9,640 airports (IATA/ICAO codes, runways, elevation).
Public data is everywhere; the value is in making it usable.
The data-cleaning was the actual project
The "just parse a CSV" part is where all the interesting bugs live:
-
Quoted fields with embedded newlines. The WPI CSV has multi-line values inside quotes. Naive
split('\n')shreds it into garbage. You need a real CSV parser that respects quoting. - Offshore oil terminals listed with 900+ meter "depths." That's the ocean floor at the mooring buoy, not a harbor depth. Left in, they made my "deepest ports" ranking pure nonsense — a cluster of open-ocean SPM buoys beating every real deep-water port. I had to detect and filter them.
-
Zeros that mean "unknown." The source uses
0for "not reported." Trust it blindly and you'll confidently render "0 m channel depth" for half the world.
Display data, or derive intelligence?
A depth of 14.5 m is boring. A depth that tells you "this berth can take a Panamax but not a Capesize" is useful. So I built a small inference layer: depth → vessel class for ports, and its aviation twin, runway length → aircraft class for airports.
The part I'm most into is the cross-modal graph: every port page lists its nearest airports, and every airport page lists its nearest seaports — computed at build time with a simple spatial grid. That linked structure is where a directory stops being a lookup table and starts being something you can explore.
14,000 pages, zero backend
The whole thing is Next.js, fully static. generateStaticParams runs over the entire dataset and pre-renders ~14,000 pages at build time. No database, no server, no runtime cost — it deploys to a CDN and is basically free to run and very fast.
The SEO lesson I didn't expect (the useful bit for other devs)
If you're building a programmatic site, here's a trap I hit face-first: dump 14,000 templated pages into Google's index and it flags you for "scaled / thin content." I learned this the hard way with an AdSense rejection.
The fix that worked: a lean core. Only the ~400 highest-quality pages per vertical are indexable and in the sitemap; the long tail stays fully live for users but is marked noindex, follow. You earn Google's trust with a small, genuinely-good set first, then expand the indexable core as the domain gains authority. If you're doing programmatic SEO, bake this in from day one instead of discovering it later.
It's free, and the data is yours
- Browse it: theportindex.online
- Download the full datasets (CSV + JSON, with documented columns): theportindex.online/data
- Also mirrored on Kaggle and Hugging Face.
All of it is built on public-domain data — use it for whatever you like.
I'd love feedback, especially from anyone in shipping, logistics, or aviation: what data or features would actually be useful to you? And for the builders — what would you make with a clean, global port + airport dataset?
Top comments (0)