Short answer
In GIS, vector features are built from three primitive geometry types defined by the OGC Simple Features standard (ISO 19125): a Point is a single location (0-dimensional), a LineString is an ordered sequence of vertices forming a path (1-dimensional), and a Polygon is an area enclosed by a closed boundary (2-dimensional). Each has a collection variant — MultiPoint, MultiLineString, MultiPolygon — that bundles several parts into one feature. Knowing exactly which type a layer holds, and how each format stores it, prevents most of the "it broke on conversion" surprises in spatial data handoffs.
The Simple Features hierarchy
The OGC/ISO Simple Features model defines a small, precise class tree. The concrete types you meet in practice:
- Point — one coordinate pair
(x, y), optionally with Z (elevation) and M (measure). A well, a sample location, a summit. - LineString — two or more vertices connected in order. A fault trace, a stream centreline, a survey line. A LinearRing is a special closed, non-self-intersecting LineString used to build polygons.
- Polygon — exactly one exterior ring defining the outer boundary, plus zero or more interior rings (holes). A lake, a licence block, a geological unit outcrop.
- MultiPoint / MultiLineString / MultiPolygon — a single feature made of several disjoint parts.
- GeometryCollection — a heterogeneous bag of geometries; supported by some formats, awkward in many tools, best avoided in deliverables.
Every geometry also carries a coordinate dimension: XY, XYZ (with elevation), XYM (with a linear measure used in linear referencing), or XYZM. A "PointZ" and a "Point" are distinct types to many systems, which matters when you load 3D survey data into a 2D-typed column.
Single vs Multi: the distinction that breaks loads
The single-part vs multi-part split is the most operationally important detail. A Polygon is one contiguous area. A MultiPolygon is one feature composed of several separate areas — Hawaii as a single "state" feature, a fragmented forest stand, an outcrop split by erosion. The same logic applies to MultiPoint and MultiLineString.
This causes trouble because many data sources contain a mix of single and multi geometries in the same layer, while strict targets (PostGIS columns, GeoPackage layers) declare one geometry type. Loading mixed Polygon/MultiPolygon data into a column typed as POLYGON fails partway through. The standard fix is to promote everything to multi:
ogr2ogr -f PostgreSQL PG:"dbname=geo" mixed.gpkg \
-nlt PROMOTE_TO_MULTI -nln geology.units
-nlt PROMOTE_TO_MULTI casts every single-part geometry to its multi equivalent so the whole layer is consistently MULTIPOLYGON. This is almost always the right call for delivery, because a MultiPolygon column can hold a one-part polygon, but a Polygon column cannot hold a two-part one.
Rings, holes, and winding order
A Polygon's geometry is its rings. The rules from the standard:
- Exactly one exterior ring; zero or more interior rings (holes), each fully inside the exterior and not overlapping each other.
- Every ring is closed — the last vertex equals the first.
- Rings must be simple — no self-intersections.
Winding order (the direction vertices are listed) encodes which side is "inside," and conventions disagree across formats, which is a frequent silent bug:
- RFC 7946 GeoJSON mandates the right-hand rule: exterior rings counter-clockwise (CCW), holes clockwise (CW).
- Esri shapefiles use the opposite: exterior rings clockwise, holes counter-clockwise.
- OGC WKB / PostGIS is tolerant on input but you should normalise;
ST_ForcePolygonCCW/ST_ForcePolygonCWset it explicitly.
When a polygon "turns inside out," fills the whole world, or loses its holes after conversion, reversed winding is the usual culprit. ogr2ogr -lco RFC7946=YES enforces correct GeoJSON winding on output.
How each format stores geometry
The same logical Point or Polygon is physically encoded differently per format:
- Shapefile holds one geometry type per file (the
.shpshape type, e.g. type 1 = Point, 3 = PolyLine, 5 = Polygon) and notably does not distinguish single from multi — a shapefile "Polygon" can contain multiple parts and rings without a separate type. It also has no separate LineString-vs-MultiLineString concept. This loose typing is why round-tripping through shapefile loses the single/multi distinction. - GeoPackage (OGC standard, a SQLite container) stores geometry as a GeoPackage-flavoured WKB blob with the declared geometry type recorded in
gpkg_geometry_columns. It cleanly supports Z/M and the multi types, one declared type per layer. - PostGIS stores EWKB in a
geometry(orgeography) column with an explicit type and SRID, e.g.geometry(MultiPolygon, 3857). You can query the actual mix withSELECT ST_GeometryType(geom), count(*) FROM units GROUP BY 1. - GeoJSON (RFC 7946) encodes geometry inline as nested coordinate arrays in WGS84 longitude, latitude order, with
"type": "Polygon"etc. It carries no separate SRID — the CRS is fixed by the spec.
Inspect what you actually have before converting:
ogrinfo -so -al data.gpkg # geometry type, feature count, SRS per layer
Worked example: auditing a delivery
Before sending a polygon layer to a client, confirm the type and validity rather than trusting the export:
-- in PostGIS
SELECT ST_GeometryType(geom) AS gtype,
ST_IsValid(geom) AS valid,
count(*)
FROM geology.units
GROUP BY 1, 2;
If you see a mix of ST_Polygon and ST_MultiPolygon, promote to multi before delivery. If valid is false for any rows, repair them:
UPDATE geology.units SET geom = ST_MakeValid(geom) WHERE NOT ST_IsValid(geom);
ST_MakeValid fixes self-intersections, ring problems, and sliver errors that would otherwise crash overlay analysis downstream.
Validation
- Confirm the declared type with
ogrinfo -soorST_GeometryType, and decide whether single/multi is consistent. - Check validity with
ST_IsValid/ the QGIS "Check Validity" tool before any overlay, buffer, or area calculation. - Verify winding if the layer is destined for GeoJSON or a web client; force RFC 7946 winding on export.
- Check dimensionality. If Z values matter (survey, geology), confirm the target column is
PointZ/PolygonZand not silently dropping the third coordinate. - Recount features after conversion; a drop means rejected geometries.
Common pitfalls and why they happen
- Mixed single/multi load failures. A strict-typed column rejects the minority type. Happens because the source mixed them and shapefile origin hid the distinction. Fix with
PROMOTE_TO_MULTI. - Inverted polygons after GeoJSON export. Reversed winding order, because shapefile and RFC 7946 disagree on ring direction.
- Lost holes. Interior rings dropped or merged during a sloppy conversion, often tied to the same winding/validity issue.
- Dropped Z values. Loading XYZ data into an XY-typed column silently flattens it; the geometry type mismatch is the cause.
- Invalid self-intersecting polygons. Digitised by hand or produced by a bad union; they pass a visual check but crash
ST_Intersection. RunST_MakeValidfirst.
Bathyl perspective
We treat the geometry type, dimensionality, winding, and validity of a layer as part of its specification, recorded alongside CRS and schema, not as an afterthought discovered when a load fails. A delivery is "done" when another team can load it into their database, run an overlay, and publish it to a web client without it turning inside out or rejecting half the rows.
Related reading
- MultiPolygon Problems in GIS
- Geometry Validity Explained
- Why Your GIS Layers Do Not Line Up
- Spatial data products