geojson-postgis
PostGIS Geometry Rows → GeoJSON FeatureCollection
Use this skill when your data already has a PostGIS geometry column (typically geom) and you need to serve it to a web map as GeoJSON.
This is the canonical pattern:
- output WGS84 (EPSG:4326) for clients
- return a FeatureCollection
- keep
propertiesas “all columns minus geom” (or explicitly selected fields)
When to use
- You have a table with
geom(geometry) and other columns - You are building or updating an API endpoint that returns map layers
- You want consistent GeoJSON structure and coordinate system
Core rules
- Serve geometry in EPSG:4326 for web clients
- GeoJSON output should be a FeatureCollection
- Properties should not include raw
geom(remove it or select explicitly)
Canonical SQL pattern (FeatureCollection)
SELECT jsonb_build_object(
'type', 'FeatureCollection',
'features', COALESCE(jsonb_agg(
jsonb_build_object(
'type', 'Feature',
'geometry', ST_AsGeoJSON(ST_Transform(t.geom, 4326))::jsonb,
'properties', (to_jsonb(t) - 'geom')
)
), '[]'::jsonb)
) AS geojson
FROM my_table t
WHERE t.geom IS NOT NULL;
Notes
COALESCE(..., '[]')ensures empty results return"features": [](not null)ST_Transform(..., 4326)ensures map-safe coordinatesto_jsonb(t) - 'geom'keeps properties clean
Selecting only certain properties (recommended for payload size)
If a table has many columns, explicitly build properties:
SELECT jsonb_build_object(
'type', 'FeatureCollection',
'features', COALESCE(jsonb_agg(
jsonb_build_object(
'type', 'Feature',
'geometry', ST_AsGeoJSON(ST_Transform(t.geom, 4326))::jsonb,
'properties', jsonb_build_object(
'id', t.id,
'name', t.name,
'status', t.status
)
)
), '[]'::jsonb)
) AS geojson
FROM my_table t
WHERE t.geom IS NOT NULL;
Returning one feature by id
Use this pattern for a single geometry row:
SELECT jsonb_build_object(
'type', 'Feature',
'geometry', ST_AsGeoJSON(ST_Transform(t.geom, 4326))::jsonb,
'properties', (to_jsonb(t) - 'geom')
) AS feature
FROM my_table t
WHERE t.id = $1
AND t.geom IS NOT NULL;
Guardrails for map endpoints
- Always require filtering (bbox, ids, or a sensible limit) for large tables
- Consider enforcing a maximum feature count
- Prefer explicit properties for large payloads
- If you frequently serve this layer, consider simplifying geometry upstream (separate skill)
Common mistakes
- Serving geometry in a projected SRID (client renders nonsense)
- Returning raw
geominproperties - Forgetting
COALESCEand returning"features": null - Returning too many features (browser crash / huge payload)
More from mmbmf1/geospatial-skills
geojson-points
Convert JSON rows with latitude/longitude fields into a GeoJSON FeatureCollection using raw PostGIS SQL.
16geojson-wkt
Convert JSON rows with WKT geometry strings into a GeoJSON FeatureCollection using raw PostGIS SQL.
13postgis-distance
Compute numeric distances safely with ST_Distance (geometry vs geography units) and pair with ST_DWithin for performance.
9postgis-dwithin
Distance-based spatial filtering with ST_DWithin, using index-friendly and unit-safe patterns.
8postgis-nearest
Find nearest features efficiently using PostGIS KNN (<->) and distance ordering (with SRID/unit guidance).
7postgis-extract-xy
Extract longitude and latitude from PostGIS geometries using ST_X and ST_Y safely.
7