WKB and WKT: Geometry Formats for Developers
WKB (Well-Known Binary) and WKT (Well-Known Text) are two standard formats for representing geometric objects, defined by the OGC Simple Features standard. They're used everywhere in GIS: PostGIS stores geometries as WKB, Shapely works with both formats, GeoJSON extends the same concepts. Understanding WKB/WKT is foundational for any developer working with geodata.
WKT: Text Representation
WKT (Well-Known Text) is a human-readable text format for geometry.
Basic Geometry Types
POINT (37.6176 55.7558)
LINESTRING (37.58 55.74, 37.60 55.75, 37.62 55.76)
POLYGON ((37.58 55.74, 37.65 55.74, 37.65 55.76, 37.58 55.76, 37.58 55.74))
MULTIPOINT ((37.61 55.75), (37.62 55.76), (37.63 55.74))
MULTILINESTRING ((37.58 55.74, 37.60 55.75), (37.61 55.75, 37.63 55.76))
MULTIPOLYGON (((37.58 55.74, 37.62 55.74, 37.62 55.76, 37.58 55.76, 37.58 55.74)),
((37.63 55.74, 37.65 55.74, 37.65 55.76, 37.63 55.76, 37.63 55.74)))
GEOMETRYCOLLECTION (POINT (37.6 55.75), LINESTRING (37.58 55.74, 37.62 55.76))
Polygons with Holes
A polygon with a cutout (courtyard inside a building):
POLYGON (
(37.58 55.74, 37.65 55.74, 37.65 55.76, 37.58 55.76, 37.58 55.74),
(37.60 55.745, 37.63 55.745, 37.63 55.755, 37.60 55.755, 37.60 55.745)
)
The first ring is the exterior. All subsequent rings are interior (holes).
3D Geometry (WKT Z)
POINT Z (37.6176 55.7558 150.5)
LINESTRING Z (37.58 55.74 100, 37.60 55.75 120, 37.62 55.76 115)
The third coordinate is height (Z). Used in 3D GIS, BIM, terrain mapping.
EWKT (PostGIS Extension)
PostGIS extends standard WKT by adding SRID (spatial reference identifier):
SRID=4326;POINT(37.6176 55.7558)
WKB: Binary Representation
WKB (Well-Known Binary) is a binary format of the same information. Each geometry is encoded as a byte sequence.
WKB Structure
Byte order (1 byte): 00 = Big Endian, 01 = Little Endian
Type (4 bytes): 1=Point, 2=LineString, 3=Polygon, 4=MultiPoint...
Coordinates: 8 bytes per number (IEEE 754 double)
Example: POINT(37.6176 55.7558) in hex WKB:
0101000000A4703D0AD7D34240AE47E17A140E4C40
WKT vs WKB Comparison
| Characteristic | WKT | WKB |
|---|---|---|
| Format | Text | Binary |
| Human-readable | Yes | No |
| Size | Larger (~2x) | Compact |
| Parse speed | Slower | Faster (10-50x) |
| Precision loss | Possible (text rounding) | None (IEEE 754) |
| Debugging | Convenient | Inconvenient |
| Network transfer | JSON-compatible | Requires base64 or hex |
| Database storage | Rare | Standard |
When to Use WKT
- Debugging and logging (coordinates are visible)
- CSV files with geometry
- Manual geometry creation in SQL
- Configuration files
- Documentation and examples
When to Use WKB
- Database storage (PostGIS, SpatiaLite)
- Transfer between libraries (Shapely, GEOS, GDAL)
- High-load data processing pipelines
- Exporting large geometry volumes
Working with WKT/WKB in PostGIS
Creating Geometry from WKT
SELECT ST_GeomFromText('POINT(37.6176 55.7558)', 4326);
SELECT 'SRID=4326;POINT(37.6176 55.7558)'::geometry;
Getting WKT/WKB from Geometry
-- To WKT
SELECT ST_AsText(way) FROM planet_osm_point LIMIT 1;
-- To WKB (hex)
SELECT ST_AsBinary(way)::text FROM planet_osm_point LIMIT 1;
-- To GeoJSON
SELECT ST_AsGeoJSON(ST_Transform(way, 4326)) FROM planet_osm_point LIMIT 1;
Working with WKT/WKB in Python (Shapely)
from shapely import wkb, wkt
from shapely.geometry import Point
# Create from coordinates
point = Point(37.6176, 55.7558)
# To WKT
wkt_str = point.wkt # 'POINT (37.6176 55.7558)'
# To WKB
wkb_bytes = point.wkb # binary bytes
wkb_hex = point.wkb_hex # hex string
# From WKT
point2 = wkt.loads('POINT (37.6176 55.7558)')
# From WKB
point3 = wkb.loads(wkb_bytes)
Shapely + PostGIS: Fast Pipeline
import psycopg2
from shapely import wkb
conn = psycopg2.connect("dbname=osm user=osm")
cur = conn.cursor()
# Get WKB directly (no intermediate WKT/GeoJSON)
cur.execute("""
SELECT ST_AsBinary(way) FROM planet_osm_polygon
WHERE building IS NOT NULL
AND way && ST_Transform(ST_MakeEnvelope(%s, %s, %s, %s, 4326), 3857)
""", (37.58, 55.74, 37.65, 55.76))
buildings = [wkb.loads(row[0]) for row in cur]
print(f"Loaded {len(buildings)} buildings")
This pipeline is 10-50x faster than WKT or GeoJSON because: 1. PostGIS returns data in native WKB without conversion 2. Shapely reads WKB directly into GEOS C structures 3. No intermediate text parsing
WKT in CSV Files
WKT is convenient for storing geometries in CSV:
id,name,type,geometry
1,Kremlin,attraction,"POLYGON ((37.613 55.752, 37.623 55.752, 37.623 55.757, 37.613 55.757, 37.613 55.752))"
2,Bolshoi Theatre,theatre,"POINT (37.6186 55.7601)"
Reading in Python:
import pandas as pd
from shapely import wkt
df = pd.read_csv("objects.csv")
df["geom"] = df["geometry"].apply(wkt.loads)
GeoJSON vs WKT vs WKB
| Format | Point Example | Size | Parsing |
|---|---|---|---|
| WKT | POINT (37.62 55.76) |
22 bytes | Text |
| WKB | 0101000000... (hex) |
21 bytes | Binary |
| GeoJSON | {"type":"Point","coordinates":[37.62,55.76]} |
48 bytes | JSON |
GeoJSON is more verbose than WKT but self-documenting. WKB is more compact than both.
WKB Fast-Path in osm2cdr
osm2cdr.ru's map rendering uses the WKB Fast-Path: data from PostGIS is passed as WKB directly to the export pipeline, bypassing intermediate text formats. This provides a 10-50x speedup compared to loading via the Overpass API (which returns XML/JSON).
Conclusion
WKT is for humans and debugging. WKB is for machines and performance. Both formats are standardized by OGC and supported by all serious GIS tools: PostGIS, QGIS, Shapely, GDAL, GEOS, JTS. For high-performance systems, always choose WKB: it's more compact, faster, and doesn't lose precision during serialization.