WKB — OGC Well-Known Binary as the Foundation of Vector GIS Databases
WKB (Well-Known Binary) is an OGC binary standard for vector geometry serialization, the foundation of nearly every modern GIS database: every ST_AsBinary() call in PostGIS, every geometry column in MySQL Spatial, every read from GeoPackage, every byte[] in a Geometry column of ParquetGeo is WKB under the hood. The format is invisible but critical: a thin infrastructure layer between SQL databases and client code, without which no reading library (GDAL, Shapely, JTS, GEOS, sf, NetTopologySuite, geo-rs) would work. WKB is a companion to WKT — the text version of the same standard — but 10–30 times more compact thanks to binary packing of double8 IEEE 754 without ASCII representation. On osm2cdr.ru WKB is our internal lingua franca: layer_builder.py uses a WKB fast-path for the PostGIS → renderer transfer, yielding 10–50x speedup vs a traditional GeoJSON parsing pipeline.

History: OGC SFA 1999 → ISO 19125 2004 → EWKB
The format was born in 1999 at the Open GIS Consortium (now Open Geospatial Consortium) as part of the Simple Features Access (SFA) v1.0 specification. SFA was the first cross-vendor standard for vector geometry, developed by a consortium of Microsoft, Oracle, Esri, IBM and others through the OGC Technical Committee. The goal was to eliminate fragmentation — each GIS vendor had its own proprietary binary format (Esri SDE binary, Oracle SDO_GEOMETRY, MapInfo TAB), and data exchange between them required painful converters. SFA defined two parallel geometry representations: WKT (Well-Known Text — human-readable, for query syntax and debug) and WKB (Well-Known Binary — compact, for storage and transfer).
In 2004 ISO ratified SFA as international standard ISO 19125-1:2004 «Geographic information — Simple feature access — Part 1: Common architecture», and Part 2 described SQL bindings (including WKB encoding rules). That cemented WKB as a formal ISO standard required for OGC SFA compliance at the SQL database level.
In 2010 OGC SFA v1.2.1 (current) added ISO/IEC support for 3D (Z) and M (Measure) coordinates by extending geometry type codes: the 1000 series for +Z, 2000 for +M, 3000 for +ZM. That produced PointZ (type=1001), PointM (type=2001), PointZM (type=3001), LineStringZ (type=1002) and so on — 28 geometry types in total.
In parallel, the PostGIS team (Refractions Research, founded by Paul Ramsey) developed EWKB (Extended WKB) — a PostGIS-specific superset adding an SRID prefix via the 0x20000000 bit flag OR'd with the geometry type. EWKB is not part of the OGC standard — it is a PostGIS extension — but it de facto spread via the PostGIS dump format, and most clients (GDAL OGR, Shapely, NetTopologySuite) optionally support reading EWKB.
In 2015 Nicklas Avén (Sweden) published an OGC discussion paper on TWKB (Tiny Well-Known Binary) — a variable-precision compressed variant using varint encoding and delta compression of coordinates. TWKB gives 50–70% size reduction vs standard WKB but is lossy (precision reduced to 4–6 decimal digits) and is not an OGC standard. PostGIS supports TWKB via the ST_AsTWKB() function.
Inside WKB: byte order, geometry type, coordinates
WKB is a stream of bytes with a fixed grammar. The file (or blob) starts with a header, followed by a payload depending on geometry type:
Byte 0: byte order flag (uint8). One byte defining endianness of all subsequent uint32 and double8 fields: 0x00 = XDR (big-endian, network byte order) or 0x01 = NDR (little-endian, Intel x86 native). NDR is used in 99% of modern systems (since x86/x64/ARM are all little-endian).
Bytes 1–4: geometry type (uint32). Geometry type identifier: 1 = Point, 2 = LineString, 3 = Polygon, 4 = MultiPoint, 5 = MultiLineString, 6 = MultiPolygon, 7 = GeometryCollection. ISO 19125 extensions for Z/M: 1001 = PointZ, 2001 = PointM, 3001 = PointZM, etc. EWKB modification: bit 0x20000000 OR'd with geometry type indicates an SRID prefix.
Bytes 5–8 (optional EWKB): SRID (uint32). Only in EWKB and only if the 0x20000000 bit is set. SRID is an EPSG code or custom spatial reference identifier (e.g. 4326 for WGS84, 3857 for Web Mercator).
Payload: coordinates. Double precision IEEE 754 (8 bytes per coordinate). For Point — just x (8 bytes) + y (8 bytes). For LineString — uint32 numPoints then numPoints × 16 bytes. For Polygon — uint32 numRings then for each ring uint32 numPoints + points. For MultiPolygon — uint32 numPolygons then for each polygon a full WKB sub-record with its own byte order + type.
Point(2.3, 49.9) example. Little-endian, no SRID, OGC standard: 0x01 01000000 7293A982C13D0240 0AD7A3703D2A4940. Total = 21 bytes. EWKB with SRID=4326 adds 4 bytes SRID = 25 bytes and the type modifier becomes 0x01000020.
WKB sizes. Point = 21 bytes; LineString with N points = 9 + 16×N bytes; Polygon with one ring of N points = 13 + 16×N bytes. Equivalent GeoJSON Point ~50 bytes ASCII, WKT ~25 bytes. WKB wins on large geometries: a city polygon with 10K vertices = ~160 KB WKB vs ~400 KB GeoJSON.
Use cases: PostGIS, MySQL, GeoPackage, ParquetGeo
PostGIS geometry columns — native storage. In PostgreSQL/PostGIS a column of type geometry or geography is physically stored as an EWKB blob (with SRID prefix). Functions ST_GeomFromWKB(bytea, srid), ST_AsBinary(geom), ST_AsEWKB(geom), ST_GeomFromEWKB(bytea) are the core API. Most spatial indexes (GiST, SP-GiST) work via bbox extraction from the WKB header.
MySQL / MariaDB Spatial. MySQL has a native GEOMETRY type and supports OGC WKB via ST_GeomFromWKB(), ST_AsBinary(), MBRContains() functions.
SQL Server geometry / geography. Microsoft SQL Server uses a WKB variant for its geometry and geography types (with extensions for curves since SQL Server 2012+). STAsBinary() and geometry::STGeomFromWKB() are standard API.
SpatiaLite BLOB columns. SpatiaLite (SQLite extension with GeoStuff) stores geometry in BLOB columns with a specific 38-byte header («GPB blob» format) followed by WKB.
GeoPackage features tables. The OGC GeoPackage standard stores geometry as a BLOB with a GeoPackage Binary Header (minimum 8 bytes: magic = GP\x00, version, flags, srid) and then a WKB payload. This makes GeoPackage fully OGC SFA compliant.
Apache Parquet / GeoParquet. GeoParquet v1.0+ (community spec, 2023) stores geometry in a Parquet column as binary type with WKB encoding. Metadata table contains SRID and bbox extent separately. Enables cloud-native analytics via DuckDB, Apache Arrow, Spark.
FlatGeobuf. Björn Harrtell's format for cloud-native streaming geometry. Structurally derived from WKB principles (byte ordering, varlen rings) but more compact for streaming reads.
Apache Arrow GeoArrow. GeoArrow extension for Arrow specifies interoperability between WKB-encoded blob storage and structured Arrow arrays (separate xs, ys arrays). WKB serves as the fallback encoding for arbitrary geometry types.
Java JTS / GEOS internal binary. JTS (Java Topology Suite, Vivid Solutions / Eclipse LocationTech) uses WKB as the primary interop format between JVM and native code. GEOS (C++ port of JTS, used by PostGIS, QGIS, GDAL) also natively reads/writes WKB.
Client-server data transfer. PostgreSQL libpq returns geometry as a hex-encoded WKB string (e.g. 01010000007293A982...). psycopg2/asyncpg parses this into Python bytes for further processing through Shapely.

Software / library support
PostGIS. ST_AsBinary(geom) returns bytea, ST_GeomFromWKB(bytea, srid) parses. For EWKB — ST_AsEWKB() / ST_GeomFromEWKB().
GDAL/OGR. Every driver supporting vector uses WKB internally. C++ API: OGRGeometry::importFromWkb(), exportToWkb(). Python: ogr.CreateGeometryFromWkb(bytes).
Shapely (Python). from shapely.wkb import loads, dumps. geom = loads(byte_data) to parse, byte_data = dumps(geom) to serialize. Hex form: dumps(geom, hex=True). SRID is not preserved in Shapely WKB (only in EWKB via dumps(geom, srid=4326)).
JTS (Java). org.locationtech.jts.io.WKBReader / WKBWriter. Supports 2D, 3D, and SRID-extended encoding. Actively maintained at Eclipse LocationTech.
GEOS (C++). GEOSWKBReader_read(), GEOSWKBWriter_write(). Used as backend in PostGIS, QGIS, GDAL, Shapely.
Boost.Geometry (C++). boost::geometry::read_wkb() / write_wkb(). Part of Boost C++ library — header-only, convenient for embedded usage.
R sf package. st_as_sfc(byte_list) for parsing WKB list into simple features collection. st_as_binary(sf_obj) for serialization.
Node.js wkx. Lightweight WKB parser for JavaScript backend (Node.js). Supports 2D, 3D, EWKB.
.NET NetTopologySuite. Port of JTS to .NET. WKBReader / WKBWriter API identical to JTS.
Rust geo / geozero. Crate geozero provides WKB I/O for the Rust ecosystem with zero-copy parsing where possible.
WKB vs alternatives
-
WKT — text version of the same OGC standard. Human-readable (
POINT(2.3 49.9)), good for SQL queries and debug, but 2–4x larger and slower to parse (requires a tokenizer). -
GeoJSON — JSON-based text format, not an OGC standard but IETF RFC 7946. Human-friendly, web-ready (browsers parse natively via
JSON.parse()), but 5–10x larger than WKB and tied to WGS84 geographic CRS only (by spec). Used for web tile APIs and Leaflet/Mapbox client-side. -
EWKB (Extended WKB) — PostGIS-specific superset with SRID prefix via bit flag 0x20000000. Not part of the OGC standard but de facto widespread through PostGIS dump format.
-
TWKB (Tiny WKB) — Nicklas Avén, OGC discussion paper 2015. Variable-precision compressed binary, varint encoding for integers, delta encoding for coordinates. 50–70% size reduction vs standard WKB but lossy. Supported in PostGIS via
ST_AsTWKB()but not an ISO standard. -
HEX-WKB. Hex-encoded WKB string (e.g.
01010000007293A982...). Often appears in SQL query results where bytea is converted to text representation. Technically identical to WKB, just with 2x size overhead from hex. -
Compressed Compact Binary (Oracle Spatial). Proprietary Oracle format for SDO_GEOMETRY. Not compatible with OGC WKB directly, but Oracle provides
SDO_UTIL.TO_WKB()/FROM_WKB()converters.
OSM2CDR integration: WKB as internal lingua franca
In OSM2CDR, WKB is our internal data transfer protocol between PostGIS and the renderer/exporter pipeline. Why — because parsing GeoJSON or WKT through an ASCII tokenizer for millions of features in Moscow took 30–60 CPU-seconds, which was the main bottleneck before 2026-01-01.
WKB fast-path in layer_builder.py. When the renderer requests layer geometry, local_osm_loader.py issues a PostGIS query SELECT ST_AsBinary(geom), tags FROM planet_osm_polygon WHERE ST_Intersects(geom, ST_MakeEnvelope(...)), gets back a bytea blob, and parses through GEOS native C bindings (bypassing Python overhead for GeoJSON json.loads()). The result is a 10–50x speedup vs the traditional pipeline. For a bbox = Moscow Garden Ring this is the difference between 45 seconds and 1.2 seconds in the data-loading stage.
ST_SimplifyPreserveTopology before transfer. To further reduce network/parsing overhead, we apply ST_SimplifyPreserveTopology(geom, tolerance) with a tolerance depending on output resolution. This removes redundant vertices while preserving shared boundaries between adjacent polygons — critical for clean SVG/DXF rendering without gaps.
User-facing «WKB» export format. OSM2CDR also offers WKB as a user-facing export format (/api/render with format=wkb). Output is a .wkb file with binary content, or .wkb.hex with hex-encoded text version (selectable via the hex=true query parameter). Use cases: DB administrators importing OSM extracts into their PostGIS/MySQL via INSERT INTO ... (geom) VALUES (ST_GeomFromWKB(decode('...', 'hex'), 4326)); GIS developers building custom rendering pipelines on JTS/GEOS/Shapely without GeoJSON parsing overhead; researchers testing OGC SFA compliance of their implementations.
SRID handling. By default we export WKB in EPSG:4326 (WGS84 geographic) — the most common CRS for OSM. Through the crs parameter you can request projection into any of the 165 supported CRS (including 122 Gauss-Kruger zones keyed to MSK numbers for Russia — an approximation, not the true MSK of a subject; the parameters of 229 real zones across 75 MSK numbers, each with a named source and confidence class, are computed by the coordinate converter). On projection, PostGIS performs ST_Transform(geom, target_srid) before ST_AsBinary so the output already contains projected coordinates.
EWKB optional. Through the ewkb=true query parameter the API returns PostGIS EWKB instead of OGC standard WKB — convenient for direct INSERT into PostGIS without explicitly specifying SRID in ST_GeomFromWKB(blob, srid).

FAQ
How does WKB differ from WKT? They encode the same geometric information; WKT is text (POINT(2.3 49.9)), WKB is binary (010100000...21 bytes). WKT is better for SQL queries and debug. WKB is better for storage, transfer, and parsing speed (binary doesn't need a tokenizer). Both specs are part of OGC SFA 1999.
How does EWKB differ from standard OGC WKB? EWKB is a PostGIS-specific extension adding an SRID prefix via bit flag 0x20000000 in the geometry type field. Standard OGC WKB has no SRID — that must be tracked separately (e.g. in dataset metadata). Most modern clients support reading EWKB, but writing is recommended in standard WKB unless you know the consumer supports EWKB.
What size is WKB for typical geometry? Point = 21 bytes (no SRID), 25 bytes (EWKB). LineString with 100 points ~ 1.6 KB. City polygon with 10K vertices ~ 160 KB. Equivalent GeoJSON is 2–5x larger.
How do I read WKB in Python? from shapely.wkb import loads; geom = loads(byte_data). If you have hex-encoded WKB (typical for PostGIS query results through psycopg2), first decode: byte_data = bytes.fromhex(hex_string); geom = loads(byte_data).
Is WKB supported in GeoJSON-only environments (Mapbox GL, Leaflet)? Not directly — browsers have no native WKB parser. You need either a server-side converter (PostGIS ST_AsGeoJSON()) or a JS library like wkx for client-side parsing. For production web maps we recommend server-side conversion to GeoJSON / vector tiles and using WKB only in backend pipelines.
What is TWKB and why didn't it become mainstream? TWKB (Tiny WKB, Nicklas Avén 2015) gives 50–70% size reduction through varint encoding and delta compression. Lossy. It didn't become mainstream because: a) tooling support is weak (only PostGIS native, GEOS partial, others don't support it), b) for big-data workflows GeoParquet with column compression already gives comparable size without lossy tradeoff, c) for web tile delivery vector tiles (MVT) are more optimal.
Can I mix big- and little-endian inside one WKB blob? Technically yes — each nested geometry has its own byte order flag. In practice all generators write consistent ordering (usually NDR/little-endian).
Conclusion
WKB is the standard wired into the foundation of GIS that nobody sees but without which nothing works. Every PostGIS query returning geometry, every GeoPackage file on disk, every GeoParquet column in a data lake, every INSERT into MySQL Spatial — under the hood it is WKB. A simple binary grammar (byte order + uint32 type + double8 coordinates), fixed by OGC SFA 1999 / ISO 19125 2004, has weathered 25+ years of evolution from the first SQL spatial databases to cloud-native analytics because its compactness, speed, and vendor neutrality turned out to be the right design tradeoffs.
On osm2cdr.ru WKB serves both as internal data transfer (10–50x speedup of layer_builder.py through the WKB fast-path) and as a user-facing export format for DB admins, GIS developers, and OGC compliance testing. Try OSM-to-WKB export for your area — the output can be directly INSERTed into PostGIS, parsed through Shapely/JTS/GEOS, or used as input for a custom GIS pipeline.
Related
- WKT — text version of OGC Simple Features Access
- GeoPackage — the modern SQLite-based OGC standard for GIS
- SpatiaLite — a lightweight spatial extension for SQLite
- GeoParquet — cloud-native columnar format for big geo data
Sources
- OGC Simple Features Access Part 1: Common Architecture (v1.2.1, 2011) — www.ogc.org/standard/sfa
- ISO 19125-1:2004 «Simple feature access» — www.iso.org/standard/40114.html
- PostGIS Manual — Well-Known Binary Representation — postgis.net/docs/using_postgis_dbmanagement.html
- JTS Topology Suite — Eclipse LocationTech — github.com/locationtech/jts
- Shapely WKB module documentation — shapely.readthedocs.io/en/stable/manual.html