GeoJSON — Everything a Developer Needs to Know
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
- [lat, lng] instead of [lng, lat] — GeoJSON uses [longitude, latitude] order. Mixing them up is the most common error.
- Unclosed polygon — first and last points of a polygon must match.
- Right-hand rule — outer ring goes counter-clockwise, inner rings (holes) go clockwise.
- File too large — for 100K+ objects, use GeoJSON-Seq or vector tiles.