openmeteo-rs
Typed async Rust client for the Open-Meteo API.
openmeteo-rs builds Open-Meteo requests with Rust enums instead of raw query
strings, validates common parameter mistakes before sending, and decodes
weather responses into nullable column-oriented time series.
Quickstart
[dependencies]
openmeteo-rs = "1"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
use openmeteo_rs::{Client, HourlyVar, Result};
#[tokio::main]
async fn main() -> Result<()> {
let client = Client::new();
let response = client
.forecast(52.52, 13.41)
.hourly([HourlyVar::Temperature2m, HourlyVar::Precipitation])
.forecast_days(1)
.send()
.await?;
if let Some(hourly) = response.hourly {
for row in hourly.iter_rows().take(6) {
println!(
"{} temp={:?} precipitation={:?}",
row.time(),
row.temperature_2m(),
row.precipitation()
);
}
}
Ok(())
}
Supported APIs
- Forecast, including multi-location forecast requests
- Historical archive
- Historical forecast
- Previous model runs
- Ensemble forecast
- Seasonal forecast
- Climate projections
- Marine forecast
- Air quality
- Satellite radiation
- Flood forecast
- Geocoding
- Elevation lookup
Most weather-like endpoints support typed variable selection, units, timezones,
cell selection, fixed or relative time windows, JSON decoding, nullable values,
and exact-token escape hatches. When Open-Meteo adds a token before the crate
exposes it as a typed variant, use the relevant other(...) constructor, for
example WeatherModel::other("exact_model_token").
Multi-Location Forecast
use openmeteo_rs::{Client, HourlyVar, Result};
# async fn example() -> Result<()> {
let client = Client::new();
let responses = client
.forecast_batch([(52.52, 13.41), (47.3769, 8.5417)])
.hourly([HourlyVar::Temperature2m])
.forecast_days(1)
.send()
.await?;
for response in responses {
println!("{},{}", response.latitude, response.longitude);
}
# Ok(())
# }
Geocode Then Forecast
use openmeteo_rs::{Client, HourlyVar, Result};
# async fn example() -> Result<()> {
let client = Client::new();
let Some(location) = client.geocode("Zurich").count(1).send().await?.into_iter().next() else {
return Ok(());
};
let forecast = client
.forecast(location.latitude, location.longitude)
.hourly([HourlyVar::Temperature2m])
.forecast_days(1)
.send()
.await?;
println!("{:?}", forecast.hourly);
# Ok(())
# }
Examples
Examples live under examples/<endpoint>/ but keep stable Cargo target names.
cargo run --example forecast_basic
cargo run --example forecast_multi_location
cargo run --example geocode_then_forecast
cargo run --example archive_basic
cargo run --example historical_forecast_basic
cargo run --example previous_runs_basic
cargo run --example ensemble_basic
cargo run --example seasonal_basic
cargo run --example climate_basic
cargo run --example marine_basic
cargo run --example air_quality_basic
cargo run --example satellite_radiation_basic
cargo run --example flood_basic
cargo run --example elevation
Limitations
These capabilities are intentionally not part of the first stable JSON release:
- FlatBuffers responses
- Polars or Arrow exports
- blocking client API
- batch builders for every endpoint family
- reverse geocoding, which Open-Meteo does not currently provide
- CSV/XLSX decoding; request JSON and export from your application instead
Attribution
Open-Meteo data is licensed under CC BY 4.0. Applications using the API should
include attribution such as Weather data by Open-Meteo.com.
This crate is MIT licensed.