GeoJSON — Everything a Developer Needs to Know

2026-02-234 min read
GeoJSONAPILeafletMapboxJavaScriptdevelopment

GeoJSON is the most popular format for transferring geodata in web applications. All mapping libraries understand it, it's human-readable, and easily processed by any programming language. If you're a developer working with maps, GeoJSON will be your primary tool.

Format Structure

GeoJSON is standard JSON with a fixed structure. Three main types:

Geometry — a single geometry

{
  "type": "Point",
  "coordinates": [37.6173, 55.7558]
}

Supported types: Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, GeometryCollection.

Coordinates are always in [longitude, latitude] order (not the other way around!). This is a common mistake — Google Maps API uses [lat, lng], while GeoJSON uses [lng, lat].

Feature — geometry with properties

{
  "type": "Feature",
  "geometry": {
    "type": "Polygon",
    "coordinates": [[[37.61, 55.75], [37.62, 55.75], [37.62, 55.76], [37.61, 55.76], [37.61, 55.75]]]
  },
  "properties": {
    "name": "Red Square",
    "building": "yes",
    "height": 25
  }
}

FeatureCollection — collection of objects

{
  "type": "FeatureCollection",
  "features": [
    { "type": "Feature", "geometry": {...}, "properties": {...} },
    { "type": "Feature", "geometry": {...}, "properties": {...} }
  ]
}

Export from osm2cdr.ru returns a FeatureCollection with a full set of OSM tags in each Feature's properties.

Using with Leaflet

Leaflet is the most popular library for interactive maps. Adding GeoJSON to a map takes three lines. TASK_ID in the URL is the task id returned by POST /api/render; the finished file lives at GET /api/download/{task_id}/geojson.

fetch('https://osm2cdr.ru/api/download/TASK_ID/geojson')
  .then(r => r.json())
  .then(data => {
    L.geoJSON(data, {
      style: feature => ({
        color: feature.properties.highway ? '#333' : '#3388ff',
        weight: feature.properties.highway ? 2 : 1
      }),
      onEachFeature: (feature, layer) => {
        if (feature.properties.name) {
          layer.bindPopup(feature.properties.name);
        }
      }
    }).addTo(map);
  });

Using with Mapbox GL JS

Mapbox GL renders GeoJSON via WebGL — faster for large datasets:

map.on('load', () => {
  map.addSource('osm-buildings', {
    type: 'geojson',
    data: 'https://osm2cdr.ru/api/download/TASK_ID/geojson'
  });

  map.addLayer({
    id: 'buildings-fill',
    type: 'fill',
    source: 'osm-buildings',
    filter: ['==', ['get', 'building'], 'yes'],
    paint: { 'fill-color': '#aaa', 'fill-opacity': 0.6 }
  });
});

Using with OpenLayers

const vectorSource = new ol.source.Vector({
  url: 'https://osm2cdr.ru/api/download/TASK_ID/geojson',
  format: new ol.format.GeoJSON()
});

const vectorLayer = new ol.layer.Vector({
  source: vectorSource,
  style: new ol.style.Style({
    stroke: new ol.style.Stroke({ color: '#333', width: 1 }),
    fill: new ol.style.Fill({ color: 'rgba(51, 136, 255, 0.3)' })
  })
});

map.addLayer(vectorLayer);

Getting GeoJSON via osm2cdr API

Via curl

curl -X POST "https://osm2cdr.ru/api/render" \
  -H "Content-Type: application/json" \
  -d '{
    "formats": ["geojson"],
    "bbox": {"min_lon": 37.61, "min_lat": 55.74,
             "max_lon": 37.63, "max_lat": 55.76},
    "config": {"layers": ["buildings", "roads"]}
  }'

Via Python

import requests

response = requests.post("https://osm2cdr.ru/api/render", json={
    "formats": ["geojson"],
    "bbox": {"min_lon": 37.61, "min_lat": 55.74,
             "max_lon": 37.63, "max_lat": 55.76},
    "config": {"layers": ["buildings", "roads", "water"]}
})
task_id = response.json()["task_id"]

# Readiness — at /api/status/{task_id}; once status == "completed",
# take the file
result = requests.get(f"https://osm2cdr.ru/api/download/{task_id}/geojson")
with open("moscow.geojson", "wb") as f:
    f.write(result.content)

GeoJSON vs GeoJSON-Seq

Standard GeoJSON loads the entire file into memory. For large datasets (100K+ objects), this is problematic. GeoJSON-Seq (RFC 8142) solves this: each Feature is written on a separate line, enabling streaming processing.

On osm2cdr.ru both formats are available: geojson for standard and geojsonseq for streaming.

Validation and Tools

  • geojson.io — visualize and edit GeoJSON in the browser.
  • geojsonlint.com — validation checking.
  • turf.js — library for spatial operations with GeoJSON (buffer, intersection, area).
  • tippecanoe — convert GeoJSON to vector tiles (PMTiles, MBTiles).
  • ogr2ogr — convert between GeoJSON and any GIS format.

Common Mistakes

  1. [lat, lng] instead of [lng, lat] — GeoJSON uses [longitude, latitude] order. Mixing them up is the most common error.
  2. Unclosed polygon — first and last points of a polygon must match.
  3. Right-hand rule — outer ring goes counter-clockwise, inner rings (holes) go clockwise.
  4. File too large — for 100K+ objects, use GeoJSON-Seq or vector tiles.

Export GeoJSON

← All articles