WKB and WKT: Geometry Formats for Developers

2026-07-165 min read
WKBWKTgeometryPostGISShapely

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.

← All articles