Async Rust client for the OpenStreetMap Overpass API. Query OSM by tag, geometry, area, name, etc., and get back typed Node/Way/Relation results — no API key required.
Overpass is the way to query OpenStreetMap by attributes. Mature clients exist for Python (overpy) and JavaScript, but Rust has been a gap. This crate fills it.
- 🌍 Run any Overpass-QL query, sync or async.
- 🔁 Built-in fallback through the public Overpass mirrors (no
429s). - 📍 Typed
Node,Way,Relationenums with tags / geometry / member access. - ⚡ Powered by
reqwest+tokio, no native deps required (pure rustls TLS). - 🪵
tracingintegration for structured logging.
[dependencies]
overpass-rs = "0.1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }use overpass_rs::OverpassClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = OverpassClient::new();
let query = r#"
[out:json][timeout:60];
area["ISO3166-1"="DE"][admin_level=2]->.de;
(
node["amenity"="cafe"](area.de);
);
out tags;
"#;
let response = client.query(query).await?;
println!("got {} cafes in Germany", response.elements.len());
for el in response.elements.iter().take(5) {
println!(" {:?}: {:?}", el.kind(), el.tag("name"));
}
Ok(())
}use overpass_rs::ql_country_tag_query;
// Build "all cafes + bakeries in Germany"
let q = ql_country_tag_query("DE", &[
("amenity", "cafe"),
("shop", "bakery"),
]);# use overpass_rs::Element;
# fn process(el: &Element) {
match el {
Element::Node { id, lat, lon, tags } => {
println!("Node {}: {:?},{:?}", id, lat, lon);
}
Element::Way { id, nodes, tags, .. } => {
println!("Way {} has {} nodes", id, nodes.len());
}
Element::Relation { id, members, tags } => {
println!("Relation {} has {} members", id, members.len());
}
}
# }Convenience accessors:
# use overpass_rs::Element;
# let el: Element = unimplemented!();
let id = el.id();
let kind = el.kind(); // "node" | "way" | "relation"
let tags = el.tags(); // &HashMap<String, String>
let name = el.tag("name"); // Option<&str>
let pos = el.lat_lon(); // Option<(f64, f64)> (only Node with geometry)By default the client tries three public Overpass mirrors in order. You can override:
# use overpass_rs::OverpassClient;
# use std::time::Duration;
let client = OverpassClient::new()
.endpoints(["https://my-private-overpass.example.com/api/interpreter"])
.timeout(Duration::from_secs(300));If you run heavy production queries, please host your own Overpass instance. The public mirrors are donated infrastructure — be a good neighbour.
cargo run --example cafes_in_berlin- Overpass-QL syntax reference
- Overpass Turbo — interactive query builder
- OSM Tag finder
- Streaming response parsing (large dataset support)
- Built-in
out geom/out skel/out bodymode helpers - XML output format support
- Rate-limited client wrapper for self-hosted instances
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT License (LICENSE-MIT)
at your option.