GeoJSON with Elasticsearch
Elasticsearch's geo_shape field type accepts GeoJSON geometry objects directly. You can index points, polygons, and any other GeoJSON geometry, then query by spatial relationship.
Create a geo_shape mapping
Map the field as geo_shape in your index. Elasticsearch reads the GeoJSON type field at index time to determine how to store and index the geometry.
PUT /locations
{
"mappings": {
"properties": {
"name": { "type": "text" },
"boundary": { "type": "geo_shape" }
}
}
}Create the index before indexing any documents. Elasticsearch cannot update a field's mapping type after documents have been indexed — you would need to reindex.
Index a GeoJSON feature
Send the GeoJSON geometry object as the field value. The coordinates array uses [longitude, latitude] order, the same as RFC 7946.
POST /locations/_doc
{
"name": "Central Park",
"boundary": {
"type": "Polygon",
"coordinates": [[
[-73.9819, 40.7681],
[-73.9580, 40.7681],
[-73.9580, 40.8006],
[-73.9819, 40.8006],
[-73.9819, 40.7681]
]]
}
}You can index any GeoJSON geometry type — Point, LineString, Polygon, MultiPolygon, and the rest. Elasticsearch applies a BKD tree index to each geometry regardless of type.
Geo shape query
Query by spatial relationship. The geo_shape query takes a shape and a relation, then returns documents whose indexed geometry satisfies that relation.
GET /locations/_search
{
"query": {
"geo_shape": {
"boundary": {
"shape": {
"type": "Point",
"coordinates": [-73.9654, 40.7829]
},
"relation": "intersects"
}
}
}
}The four relation types:
| Relation | Matches when |
|---|---|
intersects | The indexed shape overlaps the query shape (any shared area or edge) |
within | The indexed shape is fully inside the query shape |
contains | The indexed shape fully contains the query shape |
disjoint | The indexed shape has no overlap with the query shape |
intersects is the default and the most commonly used. Use within when you need to guarantee a document's geometry is completely enclosed — for example, finding all delivery stops inside a zone polygon.
Bounding box query
For point fields (geo_point), Elasticsearch provides a dedicated geo_bounding_box query. It takes top-left and bottom-right corners:
GET /locations/_search
{
"query": {
"geo_bounding_box": {
"location": {
"top_left": { "lon": -74.0, "lat": 40.8 },
"bottom_right": { "lon": -73.9, "lat": 40.7 }
}
}
}
}Note: geo_bounding_box requires a geo_point field, not geo_shape. Use geo_shape with an envelope for polygon bounding boxes.
For a geo_shape field, use the envelope type instead — a rectangle defined by its top-left and bottom-right corners:
GET /locations/_search
{
"query": {
"geo_shape": {
"boundary": {
"shape": {
"type": "envelope",
"coordinates": [[-74.0, 40.8], [-73.9, 40.7]]
},
"relation": "intersects"
}
}
}
}envelope is an Elasticsearch extension — it is not part of the GeoJSON spec, but Elasticsearch's geo_shape query accepts it as a convenience type for rectangular bounding boxes.
Indexing a FeatureCollection
Elasticsearch indexes one document per _doc. To index a GeoJSON FeatureCollection, iterate over the features array and send each feature as a separate document. The Bulk API is the standard approach for large collections:
POST /locations/_bulk
{ "index": {} }
{ "name": "Central Park", "boundary": { "type": "Polygon", "coordinates": [[[-73.9819,40.7681],[-73.9580,40.7681],[-73.9580,40.8006],[-73.9819,40.8006],[-73.9819,40.7681]]] } }
{ "index": {} }
{ "name": "Times Square", "boundary": { "type": "Point", "coordinates": [-73.9855, 40.7580] } }Each line pair is a metadata line (the action) followed by the source document. Keep bulk requests under 100 MB.
Watch out: Elasticsearch uses
[longitude, latitude]— the same order as GeoJSON — but some Elasticsearch client libraries accept{ lat, lon }objects forgeo_pointfields. Don't mix the two formats in the same document.
For GeoJSON format reference, see What is GeoJSON?. For PostgreSQL with PostGIS, see GeoJSON with PostGIS. For indexing GeoJSON via Python, see GeoJSON with Python.
If you're building a map interface over an Elasticsearch backend, Element Editor is an open-source React library for drawing and editing the GeoJSON shapes you store and query.
Continue reading
- GeoJSON with PostGIS and PostgreSQL
How to store, query, and export GeoJSON in PostgreSQL using PostGIS — ST_AsGeoJSON, ST_GeomFromGeoJSON, and building a FeatureCollection in SQL.
- GeoJSON with Python
How to read, write, filter, and convert GeoJSON in Python — using the json stdlib, the geojson library, geopandas, Shapely, and Folium.
- FoundationsWhat is GeoJSON?
GeoJSON is an open standard (RFC 7946) for encoding geographic features as JSON. Learn the format, geometry types, and how it's used.

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.