CHAPTER 17
GeoJSON — the universal format
Every GeoJSON geometry type, winding order rules, the lon/lat ordering trap, and the validation rules that every developer trips over.
GeoJSON (RFC 7946) is the de facto interchange format for geographic data. It's what every mapping library reads and writes, and it has several sharp edges that trip up developers.
GeoJSON is plain JSON. There's nothing special about it beyond a specific schema. You can create, read, and edit it with any text editor or JSON.parse. The full spec is RFC 7946 — 20 pages, worth reading once.
Geometry types
GeoJSON has nine types:
| Type | Description | Example |
|---|---|---|
Point | Single coordinate | A shop location |
LineString | Ordered list of points | A road segment |
Polygon | Closed ring(s) | A country boundary |
MultiPoint | Collection of points | Bus stops |
MultiLineString | Collection of lines | A split route |
MultiPolygon | Collection of polygons | Countries with islands |
GeometryCollection | Mix of any geometries | — |
Feature | Geometry + properties | A labelled location |
FeatureCollection | Array of Features | A layer |
Feature and FeatureCollection are the wrapper types you'll use most. Raw geometry types (Point, Polygon, etc.) carry no attributes; wrapping them in a Feature lets you attach a properties object with metadata like names, IDs, and display values.
GeoJSON geometry types
{
[type] "Feature",
"geometry": {
[type] "Point",
"coordinates": [
74.3587,
31.5204
]
},
"properties": {
"name": "Lahore",
"population": 13000000
}
}→ Geometry + arbitrary properties.
The lon/lat trap
GeoJSON coordinates are [longitude, latitude] — the opposite of most mapping APIs.
{ "type": "Point", "coordinates": [74.3587, 31.5204] }
// ^ lon first ^ lat second
Google Maps, Apple Maps, Leaflet — they all use (lat, lon). GeoJSON follows the (x, y) = (easting, northing) convention from cartography. This trips up every developer at least once.
// ❌ Wrong — swapped
const point = { type: "Point", coordinates: [31.5204, 74.3587] };
// ✅ Correct
const point = { type: "Point", coordinates: [74.3587, 31.5204] };
Winding order (right-hand rule)
RFC 7946 requires counter-clockwise exterior rings and clockwise interior rings (holes). This is the right-hand rule: if you walk the boundary with your right hand pointing outward, the interior is to your left.
Counter-clockwise exterior (correct): Clockwise interior/hole (correct):
[0,1] → [1,1] → [1,0] → [0,0] → [0,1] [0.2,0.8] → [0.2,0.2] → [0.8,0.2] → [0.8,0.8]
Winding order matters because GeoJSON needs a convention to distinguish the "inside" from the "outside" of a polygon, especially for global-spanning polygons where either side could be the interior. Some consumers (Mapbox, PostGIS) auto-correct winding order. Others reject invalid GeoJSON silently. Always validate.
import { rewind } from "@turf/rewind";
const corrected = rewind(myGeoJSON, { reverse: false });
Continue reading "GeoJSON — the universal format"
You've reached the end of the free preview. Unlock all 22 paid chapters, including distance math, bearings, polygons, spatial indexing, and 3D map rendering — plus a downloadable PDF and the companion code repo.
- All 22 paid chapters with worked examples
- Downloadable PDF for offline reading
- Companion GitHub repo (JavaScript + Python)
- Free updates for life
Multiple payment options including Wise, PayPal, and bank transfer.
Related chapters
- Polygons — area, centroid, and containment — the geometry type most often serialised
- The antimeridian — the bug that breaks every map — GeoJSON's antimeridian rules
- Coordinate transforms — converting between CRS — GeoJSON is WGS84-only by spec