- Go 95.7%
- Python 2.6%
- Java 1.5%
- Shell 0.2%
| cmd/broom | ||
| docs | ||
| examples/router | ||
| internal | ||
| LICENSES | ||
| pkg/routing | ||
| testdata | ||
| tools/oracles | ||
| .gitignore | ||
| .kata.toml | ||
| broom-design.md | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| NOTICE.md | ||
| README.md | ||
broom
An offline OpenStreetMap routing engine in Go. Build a graph from an OSM PBF, open it as a library, and calculate routes for walking, mountain bikes, cars and trail motorcycles. No routing server required.
- Pure Go; builds with
CGO_ENABLED=0. - Memory-mapped, profile-independent graphs and per-profile metrics.
- BRouter
.brfprofile support, runtime overrides, and four original profiles. - Elevation sampled at graph build time.
- Managed Geofabrik downloads and graph caching.
- GPX and GeoJSON export, a CLI, and an OSRM-shaped debug HTTP API.
Status: pre-release. The implementation works, but the public API is not frozen and routing-quality targets are still being evaluated. See current limitations before depending on it.
Install
Requires Go 1.27 or newer. From a checkout:
CGO_ENABLED=0 go build -o broom ./cmd/broom
./broom --help
Or install the current published source revision:
CGO_ENABLED=0 go install github.com/rubiojr/broom/cmd/broom@latest
The executable goes into GOBIN, or $(go env GOPATH)/bin by default. For
repeatable builds, select a specific published version or commit instead of
@latest. Java and containers are needed only for optional oracle experiments.
First route
This downloads the smallest Geofabrik region covering the two waypoints, fetches elevation, builds a graph, and writes a walking route through Monaco:
./broom route --profile walk \
--from 7.4197,43.7384 --to 7.4276,43.7392 \
--format geojson --output monaco.geojson
Coordinates are always longitude, latitude. Distances and elevations are metres; durations are seconds. The first managed route needs network access and can take much longer than subsequent queries. Elevation downloads can be much larger than a small region's PBF.
For an explicit region and reusable graph:
./broom setup --profile walk monaco
Keep the graph path from the setup output. Passing it to route uses the local
graph directly, without revalidating managed downloads:
./broom route --profile walk \
--from 7.4197,43.7384 --to 7.4276,43.7392 \
--format gpx --output monaco.gpx /path/to/monaco.broom
For a quick checkout smoke test without downloads, use the pinned Andorra
fixture. Run this in the repository root; andorra.broom should be a new file:
gzip -dc testdata/andorra-routing.broom.gz > andorra.broom
./broom route --profile mtb \
--from 1.53034,42.498586 --to 1.522465,42.504917 \
--format geojson --output andorra.geojson andorra.broom
Library
pkg/routing manages region selection, data acquisition, graph building and
queries. This is the shortest route from coordinates to a result:
package main
import (
"context"
"fmt"
"log"
"github.com/rubiojr/broom/pkg/routing"
)
func main() {
manager, err := routing.New(routing.Options{})
if err != nil {
log.Fatal(err)
}
result, err := manager.Route(context.Background(), routing.Request{
Profile: "walk",
Waypoints: []routing.Waypoint{
{Point: routing.Point{Lon: 7.4197, Lat: 43.7384}},
{Point: routing.Point{Lon: 7.4276, Lat: 43.7392}},
},
}, routing.RouteOptions{})
if err != nil {
log.Fatal(err)
}
fmt.Printf("%.0f metres, %.0f seconds\n", result.Route.Distance, result.Route.Duration)
fmt.Println("graph:", result.GraphPath)
}
Manager.Route closes its internal router before returning. For repeated or
offline queries, call manager.Open(graphPath) and reuse the returned router;
call Close() when finished. SetupRegion also returns a caller-owned router.
Managed setup revalidates source metadata, so it is not an offline-open API.
For direct control of local graphs, use
routing.Open(graphPath, routing.RouterOptions{}) → Router.Route(ctx, request)
→ Router.Close(). routing.Build builds from local PBF/HGT inputs.
routing.LoadProfile / routing.ParseProfile configure custom profiles;
routing.WriteGPX / routing.WriteGeoJSON export results.
pkg/routing is the sole public library package. The four-waypoint example
is runnable with go run ./examples/router and uses managed downloads.
Profiles and local data
# Build once. The HGT directory may use flat or latitude-band subdirectories.
./broom build --output region.broom --elevation /path/to/hgt region.osm.pbf
# Prepare an MTB metric before the first query.
./broom customize --profile mtb region.broom
# Load a custom BRF or change a global variable.
./broom route --profile mtb --set mtb_hard_factor=2 \
--from 1.53034,42.498586 --to 1.522465,42.504917 region.broom
build --elevation auto downloads elevation; --elevation none builds without
it. Choose deliberately: changing elevation requires rebuilding the graph.
--slim omits names and OSM way IDs. Profile changes require new metrics, not
new topology. See usage and compatibility.
Development and evidence
go test ./...
go vet ./...
staticcheck ./...
The normal tests use local fixtures. Optional Java and country-scale tests document their required inputs and skip when those inputs are absent.
- Current status and v1 work
- Usage, ownership and compatibility
- Migration to the consolidated API
- BRF conformance
- Elevation model
- Turn restrictions
- Oracle harness
- Full-route Andorra evidence
- Design and targets
License
Broom's original code and profiles are MIT-licensed. The bundled BRouter lookup table retains its upstream MIT notice. OpenStreetMap-derived fixtures and graph data have separate ODbL terms. See NOTICE.md for attribution and third-party material.