# geodb-rs
[](https://crates.io/crates/geodb-core)
[](https://docs.rs/geodb-core)
[](https://opensource.org/licenses/MIT)
A high-performance, pure-Rust geographic database with countries, states/regions, cities, aliases, phone codes, currencies, timezones, and WebAssembly support.
This repository is a **Cargo workspace** containing:
- **`geodb-core`** β main geographic database library (published on crates.io)
- **`geodb-wasm`** β WebAssembly bindings + browser demo (Trunk-based)
- **`geodb-cli`** β optional CLI (future)
---
# Overview
`geodb-core` provides:
- π Fast loading from compressed JSON or binary cache
- πΎ Automatic caching based on dataset file and filters
- π Flexible lookups: ISO codes, names, aliases, phone codes
- π Countries, states/regions, cities, populations
- πΊ Accurate metadata: region, subregion, currency
- π Phone code search
- β± Zero-copy internal model
- π¦ Pure Rust β no unsafe
- πΈ WASM support via `geodb-wasm`
The dataset is adapted from
https://github.com/dr5hn/countries-states-cities-database
(licensed under **CC-BY-4.0**, attribution required).
> Important: Data source we rely on
>
> geodb-core ships and expects the upstream dataset from the following file in the dr5hn/countries-states-cities-database repository:
>
> https://github.com/dr5hn/countries-states-cities-database/blob/master/json/countries%2Bstates%2Bcities.json.gz
>
> The default loader uses a copy of this file placed under `crates/geodb-core/data/countries+states+cities.json.gz` and builds a binary cache alongside it. If you update or replace the dataset, ensure it retains the same JSON structure. Please observe the CCβBYβ4.0 license and attribution of the upstream project.
---
# Installation
### For Rust applications
```toml
[dependencies]
geodb-core = "0.2"
```
### For WebAssembly (browser/Node)
```toml
[dependencies]
geodb-wasm = "0.2"
```
---
# Quick Start
```rust
use geodb_core::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let db = GeoDb::<StandardBackend>::load()?;
if let Some(country) = db.find_country_by_iso2("US") {
println!("Country: {}", country.name());
println!("Capital: {:?}", country.capital());
println!("Phone Code: {}", country.phone_code());
println!("Currency: {}", country.currency());
}
Ok(())
}
```
---
# Loading & Caching
## Default loading
Loads from:
```
geodb-core/data/countries+states+cities.json.gz
```
Creates automatic cache:
```
countries+states+cities.json.ALL.bin
```
```rust
let db = GeoDb::<StandardBackend>::load()?;
```
## Load from a custom file
```rust
let db = GeoDb::<StandardBackend>::load_from_path(
"path/to/worlddata.json.gz",
None,
)?;
```
Cache becomes:
```
worlddata.json.ALL.bin
```
## Filtered loading (ISO2)
```rust
let db = GeoDb::<StandardBackend>::load_filtered_by_iso2(&["DE", "US"])?;
```
Cache:
```
countries+states+cities.json.DE_US.bin
```
Cache rules:
```
<dataset_filename>.<filter>.bin
```
---
# Usage Examples
### List all countries
```rust
use geodb_core::prelude::*;
let db = GeoDb::<StandardBackend>::load()?;
for country in db.countries() {
println!("{} ({})", country.name(), country.iso2());
}
```
### Find by ISO code
```rust
if let Some(country) = db.find_country_by_iso2("DE") {
println!("Found {}", country.name());
}
```
### Country details
```rust
if let Some(fr) = db.find_country_by_iso2("FR") {
println!("Capital: {:?}", fr.capital());
println!("Currency: {}", fr.currency());
println!("Region: {}", fr.region());
}
```
### States & cities
```rust
if let Some(us) = db.find_country_by_iso2("US") {
let states = us.states();
if let Some(ca) = states.iter().find(|s| s.state_code() == "CA") {
for city in ca.cities() {
println!("{}", city.name());
}
}
}
```
### Phone search
```rust
let countries = db.find_countries_by_phone_code("+44");
```
### Search for cities named βSpringfieldβ
```rust
let results: Vec<_> = db.countries()
.iter()
.flat_map(|country| {
country.states().iter().flat_map(move |state| {
state.cities().iter()
.filter(|c| c.name() == "Springfield")
.map(move |c| (country.name(), state.name(), c.name()))
})
})
.collect();
```
---
# WebAssembly (`geodb-wasm`)
Exports:
- `search_country_prefix`
- `search_countries_by_phone`
- `search_state_substring`
- `search_city_substring`
- `smart_search`
- `get_stats`
To run locally:
```bash
cd crates/geodb-wasm
cargo install trunk
trunk serve
```
Live demo:
**https://trahe.eu/geodb-rs.html**
---
# Workspace Layout
```
geodb-rs/
βββ crates/
β βββ geodb-core
β βββ geodb-wasm
β βββ geodb-cli (planned)
βββ data/
β βββ countries+states+cities.json.gz
β βββ geodb.standard.bin
βββ examples/
βββ scripts/
βββ README.md
```
---
# Performance
- Initial load from JSON: ~20β40ms
- Cached load: ~1β3ms
- Memory use: 10β15MB
- Fully zero-copy internal model
---
# Contributing
### Before submitting PRs:
```
cargo fmt
cargo clippy --all-targets -- -D warnings
cargo test --workspace
cargo doc --workspace
cargo sort -cwg
taplo format --check
cargo deny check
```
---
# License
### Code
MIT License.
### Data Attribution (Required)
This project includes data from:
**countries-states-cities-database**
https://github.com/dr5hn/countries-states-cities-database
Licensed under **Creative Commons Attribution 4.0 (CC-BY-4.0)**.
Attribution is required if you redistribute or use the dataset.
---
# Links
- Repo: https://github.com/holg/geodb-rs
- Docs: https://docs.rs/geodb-core
- Crate: https://crates.io/crates/geodb-core
---
Made with β€οΈ in Rust.