Learn

What is GeoJSON?

GeoJSON is an open standard (RFC 7946) for encoding geographic features as JSON.

TL;DR
  • GeoJSON encodes geographic features as JSON — valid JSON parseable by any language with a JSON library
  • Seven geometry types: Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon, GeometryCollection
  • Coordinates are [longitude, latitude] — longitude first, always
  • All coordinates must use WGS 84 (EPSG:4326); the crs member was removed in RFC 7946
  • Feature wraps geometry with properties; FeatureCollection holds multiple Features

It stores points, lines, polygons, and collections of these shapes in a format any JSON parser can read. A .geojson file is a plain text file. Open it in a text editor and you can read it. Paste it into JSON.parse() and you have a JavaScript object. No binary decoding, no proprietary library, no install step.

What you need to know

  • It's valid JSON. Every GeoJSON document passes JSON.parse(). The structure adds constraints — required type fields, specific geometry shapes — but not a new format.
  • Seven geometry types. Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon, GeometryCollection. These are the only valid geometry type values.
  • Features wrap geometry and properties. A Feature object carries a geometry and a properties object for attributes (name, category, population — whatever your data needs). A FeatureCollection wraps an array of Features.
  • Coordinates are [longitude, latitude]. Not [latitude, longitude]. This trips up most developers the first time. Longitude (east-west, the x axis) comes first.
  • RFC 7946 is the spec. Published by the IETF in August 2016, it superseded the informal 2008 GeoJSON spec. The coordinate order rule and the WGS 84 requirement both come from RFC 7946.

Why GeoJSON exists

Before GeoJSON, the two dominant formats for exchanging geographic data were Shapefile and KML.

Shapefile is an ESRI format from 1998. A "file" is actually four files at minimum: .shp (geometry), .dbf (attributes), .shx (shape index), .prj (projection). The encoding is binary. Reading one requires a dedicated library. Field names are capped at 10 characters. Shapefiles are still everywhere — decades of data exist in this format — but they were never designed for the web.

KML is an XML-based format developed by Google for Google Earth, standardised by the OGC in 2008. It can encode styling, camera positions, network links, and ground overlays alongside geometry. That breadth is also the problem: a KML file is verbose XML with a schema most HTTP stacks have no native support for.

JSON won for a straightforward reason: it's already in every HTTP stack. The browser has JSON.parse(). Node.js has it. Python has json.loads(). Go has encoding/json. A server sending GeoJSON over a REST API needs no special content-negotiation. A client receiving it needs no special library. The data structure is immediately inspectable in any debugger.

RFC 7946 formalised this in 2016. It added the WGS 84 requirement (all coordinates must be in EPSG:4326), specified winding order for polygon rings, and clarified coordinate ordering. The 2008 spec had left several of these ambiguous.

Geometry types

GeoJSON defines seven geometry types:

TypeRepresentsExample use
PointA single locationA coffee shop, a GPS fix
MultiPointMultiple locations, one entityA chain's store locations
LineStringA path between two or more pointsA road, a river, a route
MultiLineStringMultiple disconnected paths, one entityA road network around a roundabout
PolygonA closed area with optional holesA park boundary, a country outline
MultiPolygonMultiple disconnected areas, one entityA country with islands
GeometryCollectionMixed geometry types, one entityA named place that is both a point and a polygon

Each geometry object has a type string and a coordinates array. The nesting depth of coordinates increases with the type.

Point — coordinates is a single position [longitude, latitude]:

{
  "type": "Point",
  "coordinates": [-0.1276, 51.5074]
}

MultiPoint — coordinates is an array of positions:

{
  "type": "MultiPoint",
  "coordinates": [
    [-0.1276, 51.5074],
    [2.3522, 48.8566]
  ]
}

LineString — coordinates is an array of positions forming a path:

{
  "type": "LineString",
  "coordinates": [
    [-0.1276, 51.5074],
    [2.3522, 48.8566],
    [13.4050, 52.5200]
  ]
}

MultiLineString — coordinates is an array of LineString coordinate arrays:

{
  "type": "MultiLineString",
  "coordinates": [
    [[-0.12, 51.50], [-0.11, 51.51]],
    [[-0.13, 51.49], [-0.12, 51.50]]
  ]
}

Polygon — coordinates is an array of rings. The first ring is the outer boundary. Additional rings are holes. Each ring closes by repeating the first position at the end:

{
  "type": "Polygon",
  "coordinates": [
    [
      [2.2945, 48.8584],
      [2.2950, 48.8584],
      [2.2950, 48.8590],
      [2.2945, 48.8590],
      [2.2945, 48.8584]
    ]
  ]
}

MultiPolygon — coordinates is an array of Polygon coordinate arrays:

{
  "type": "MultiPolygon",
  "coordinates": [
    [
      [[-157.9, 21.3], [-157.6, 21.3], [-157.6, 21.5], [-157.9, 21.5], [-157.9, 21.3]]
    ],
    [
      [[-156.6, 20.5], [-156.3, 20.5], [-156.3, 20.9], [-156.6, 20.9], [-156.6, 20.5]]
    ]
  ]
}

GeometryCollection — geometries is an array of geometry objects (any mix of types):

{
  "type": "GeometryCollection",
  "geometries": [
    { "type": "Point", "coordinates": [2.3522, 48.8566] },
    {
      "type": "Polygon",
      "coordinates": [[[2.25, 48.82], [2.47, 48.82], [2.47, 48.90], [2.25, 48.90], [2.25, 48.82]]]
    }
  ]
}

For the full geometry reference — winding order, nesting rules, when to choose Multi vs. Collection — see GeoJSON geometry types.

Feature and FeatureCollection

Bare geometries are valid GeoJSON, but most real-world data uses Feature and FeatureCollection. The hierarchy adds identity and attributes to geometry.

A Feature wraps one geometry with an optional id and a properties object:

{
  "type": "Feature",           // required, always "Feature"
  "id": "eiffel-tower",        // optional — string or number
  "geometry": {
    "type": "Point",
    "coordinates": [2.2945, 48.8584]
  },
  "properties": {              // any key-value pairs, or null
    "name": "Eiffel Tower",
    "height_m": 330,
    "opened": 1889
  }
}

A FeatureCollection wraps multiple Features into one document — the format most APIs and map libraries expect:

{
  "type": "FeatureCollection",  // required, always "FeatureCollection"
  "features": [                 // array of Feature objects
    {
      "type": "Feature",
      "id": "london",
      "geometry": {
        "type": "Point",
        "coordinates": [-0.1276, 51.5074]  // [longitude, latitude]
      },
      "properties": {
        "name": "London",
        "population": 8982000
      }
    },
    {
      "type": "Feature",
      "id": "paris",
      "geometry": {
        "type": "Point",
        "coordinates": [2.3522, 48.8566]
      },
      "properties": {
        "name": "Paris",
        "population": 2161000
      }
    }
  ]
}

The properties object can hold any JSON-serialisable values — strings, numbers, booleans, arrays, nested objects. RFC 7946 imposes no schema on properties.

When geometry is null, the Feature represents a thing that exists but has no known location — a valid state the spec explicitly allows.

The coordinate order trap

GeoJSON coordinates are [longitude, latitude].

Not [latitude, longitude]. The order is longitude first.

This is the most common mistake in GeoJSON. It's silent — the document is syntactically valid either way, but if you swap the order, London ends up somewhere in the Atlantic Ocean.

The mnemonic: GeoJSON follows mathematical convention. Longitude is the x axis (east-west); latitude is the y axis (north-south). x comes before y. Always.

The confusion comes from how we read addresses aloud. We say "51.5° North, 0.1° West" — latitude first, the way you'd read a grid reference on a map. GeoJSON ignores that convention in favour of the x/y ordering every graphics and geometry library expects. It is, as RFC 7946 acknowledges in a footnote, "a common source of errors."

The fix is mechanical: when you're converting from a lat/lng pair (which most geocoding APIs return), reverse the order before writing to GeoJSON. [lat, lng] → [lng, lat].

What GeoJSON is not

Understanding what GeoJSON does not include helps set correct expectations for what it can and can't do on its own.

No styling

GeoJSON encodes geometry and attributes. It has no concept of colour, line width, fill opacity, icon, or label. The rendering layer decides how each feature looks.

In Leaflet, styling lives in the style option passed to L.geoJSON(). In Mapbox GL JS, it lives in the layer's paint and layout properties. In D3, it lives in CSS and the attr() call.

This separation is intentional. The same GeoJSON file can be rendered as a black-and-white print map, a neon web map, and a colour-coded choropleth — with no changes to the data. Styling in the data would couple the format to a specific renderer.

No elevation by default

RFC 7946 permits a third value in coordinate arrays, conventionally treated as altitude in metres:

{ "type": "Point", "coordinates": [2.2945, 48.8584, 276] }

However, the spec explicitly states that "the interpretation and meaning of altitude is application-specific." PostGIS ignores it. Leaflet ignores it. Some 3D mapping tools read it; many don't.

If your use case depends on elevation — building heights, terrain, flight paths — use a format designed for 3D: CityJSON (urban models), CesiumJS's CZML, or glTF for 3D meshes. GeoJSON's third coordinate is not a reliable 3D transport.

No projection metadata

All GeoJSON coordinates must be in WGS 84 (EPSG:4326). This is not a recommendation — it is a requirement of RFC 7946.

Earlier GeoJSON documents (pre-2016) sometimes included a crs member specifying a different coordinate reference system. RFC 7946 removed crs. If your source data is in a local CRS — British National Grid (EPSG:27700), UTM zones, or State Plane — you must reproject to WGS 84 before writing GeoJSON.

Tools for reprojection: ogr2ogr -t_srs EPSG:4326, geopandas.to_crs(epsg=4326), or the Proj library in most languages. Skipping this step produces coordinates that are technically valid GeoJSON but geographically wrong by potentially thousands of metres.

Where GeoJSON is used

Databases — PostgreSQL with PostGIS stores geometry in a native geometry column and exports it as GeoJSON with ST_AsGeoJSON(geom). MongoDB accepts GeoJSON Point objects directly in any field typed with a 2dsphere index, enabling $near and $geoWithin queries. Elasticsearch indexes any GeoJSON geometry in a geo_shape field and supports intersect, within, and bounding box queries.

APIs and file hosts — GitHub renders .geojson files in any repository as an interactive map. No configuration required — push the file and GitHub displays it. Mapbox's Data API accepts GeoJSON as an upload format for tilesets. The Overpass API (OpenStreetMap query tool) returns GeoJSON on request.

Client libraries — Leaflet's L.geoJSON(data) renders a FeatureCollection as map layers in one call. Mapbox GL JS treats GeoJSON as a source type: map.addSource('zones', { type: 'geojson', data: url }), then one or more layers reference the source. D3 renders GeoJSON directly through its geoPath() generator, which handles projection from geographic coordinates to SVG pixel coordinates.

Frequently asked questions

What is GeoJSON used for?
GeoJSON is used to represent geographic features — points, lines, and polygons — as JSON. Common uses include storing location data in databases, serving geographic data from APIs, rendering maps in web applications, and exchanging data between GIS tools.
Is GeoJSON the same as JSON?
GeoJSON is a subset of JSON. Every GeoJSON document is valid JSON, but not every JSON document is valid GeoJSON. GeoJSON adds a specific structure: a required 'type' field, a defined set of geometry types, and a coordinate array in [longitude, latitude] order.
What is the difference between GeoJSON and Shapefile?
A Shapefile is a set of at least four binary files (.shp, .dbf, .shx, .prj). GeoJSON is a single text file. GeoJSON is human-readable, natively parseable in any language with a JSON library, and served easily over HTTP. Shapefiles are more compact for large datasets and carry projection metadata. Most GIS tools read both.
What is a GeoJSON FeatureCollection?
A FeatureCollection is the top-level GeoJSON object that holds an array of Features. Each Feature wraps a geometry (Point, Polygon, etc.) and a properties object. Most APIs and libraries work with FeatureCollections rather than individual geometries.
Does GeoJSON support 3D coordinates?
RFC 7946 allows a third coordinate value in coordinate arrays. Its meaning is not defined by the spec — it is typically treated as elevation in metres, but behaviour varies across tools. For reliable 3D, use a format designed for it (CityJSON, glTF) rather than depending on GeoJSON's third coordinate.
What is application/geo+json?
application/geo+json is the registered MIME type for GeoJSON files (registered in RFC 7946). Use it as the Content-Type header when serving GeoJSON from an API: Content-Type: application/geo+json.
What databases support GeoJSON?
PostgreSQL with the PostGIS extension stores and queries GeoJSON via ST_GeomFromGeoJSON() and ST_AsGeoJSON(). MongoDB supports GeoJSON natively with its 2dsphere index type. Elasticsearch indexes GeoJSON features using the geo_shape field type. SQLite supports GeoJSON through the SpatiaLite extension.
Is GeoJSON an open standard?
Yes. GeoJSON is defined by RFC 7946, published by the IETF (Internet Engineering Task Force) in August 2016. It superseded the earlier GeoJSON specification from 2008. The RFC is freely available at [tools.ietf.org/html/rfc7946](https://tools.ietf.org/html/rfc7946).

If you need to draw and edit GeoJSON in a React application, Element Editor is an open-source library (MIT) that handles the editing layer on top of Leaflet or MapLibre.

Continue reading

Mike Acler

Mike Acler

Design engineer and creator of Element Editor, an open-source map drawing and GeoJSON editing library for React. Writes about web cartography and GIS tooling.