Routing docs

How routing works

How geolith Routing works: OpenStreetMap in, a road graph cut into tiles by the builder, stored as 64 KiB zstd blocks in the routing part of a .glx file, read in byte ranges by a Rust router, answered as Valhalla-compatible JSON. In development, not deployed for public use.

By · Updated

Status: in development. Not deployed for public use. The builder writes routing files and the router answers from them; nothing is offered as a service yet. What is done and what is left is on Status and roadmap.

The steps

input → builder → .glx routing part → router → response
  1. Input. An OpenStreetMap extract (.osm.pbf).
  2. Builder. The geolith builder reads the roads, applies tag rules, builds edges, sets access on each edge and reads turn restrictions. It then runs the enhancer, builds the road hierarchy and adds shortcuts. It cuts the graph into graph tiles on three grids: 4°, 1° and 0.25° cells.
  3. The routing part. The builder writes each tile as fixed 64 KiB blocks, each its own zstd frame, behind a per-tile block directory, after a tile index, as the routing part of a .glx file. See The routing part.
  4. Router. The Rust router library keeps the tile index in memory and asks for the blocks a request needs; the program around it fetches them with HTTP range requests or file reads.
  5. Response. The router answers with Valhalla's response bodies. See API.

The builder command:

geolith --output-format routing --osm-pbf berlin.osm.pbf \
  --routing-output berlin-routing.glx

Add --routing-predicted-speeds <dir> to store historical speeds in the tiles; see Traffic and live data.

What happens to a request

  1. Snap. Each location is matched to the nearest road edge the chosen costing (auto, pedestrian or bicycle) may use.
  2. Search. For /route, a bidirectional A* search runs from both ends over the road hierarchy, honouring turn restrictions. /isochrone runs a one-to-all search, /sources-to-targets a many-to-many search, and the map matching endpoints match a GPS trace to the roads.
  3. Build the answer. For a route, the router adds up the length and time, encodes the shape as a polyline with precision 6, and writes the maneuvers with English text and spoken (verbal_*) instructions.

The data, end to end

QuestionAnswer
What is the input?An OpenStreetMap .osm.pbf extract. Berlin is built and tested; a country and the planet are not built yet.
How is the input made?Downloaded from OpenStreetMap (planet file or a regional extract). geolith does not edit it.
Where is it stored?In one .glx file, in its routing part: R2, S3, any server that answers Range requests, or local disk.
How is it ingested?It is not. The file is the database: there is no import step, no database server and no index to load beyond the tile index the router reads on start.
How is it used?The router reads the tile index once, then fetches only the blocks a request touches.
How is it accessed?By HTTP range requests (R2 or any HTTP server) or file reads (local disk). Adjacent blocks are merged into one request.
How is it served?A Cloudflare Worker app serves the six endpoints. It runs as a test deployment on workers.dev only; nothing is deployed for public use.
How is it kept safe?The file is read-only. Tile decoders are bounds-checked Rust with no unsafe. Every tile is treated as untrusted input and refused whole if malformed, never read in part. The request path does not panic on bad input.

Inputs, now and planned

InputUseStatus
OpenStreetMap .osm.pbfRoads, access, turn restrictions, namesNow
Historical speeds (CSV)Speed by time of week, free-flow and constrained-flow speeds per edgeNow (--routing-predicted-speeds)
Administrative boundariesDriving side and country rulesNext, before launch
Time zonesLocal time for time-dependent rulesNext, before launch
Overture Maps transportationRoads and names from OvertureLater
ElevationGrades on edgesLater
GTFSPublic transitLater