Switching from Nominatim
You run Nominatim because it's free and self-hosted. You also run PostgreSQL, an osm2pgsql import that
takes hours and tens of gigabytes, and a server you can't ship inside an app or run in a browser.
Mailwoman gives you the same HTTP contract from a SQLite file — so you can move your client without
rewriting it, then drop the database stack.
One command
npx @mailwoman/nominatim serve --port 8080
Point your client at it. With geopy:
from geopy.geocoders import Nominatim
geo = Nominatim(domain="localhost:8080", scheme="http")
geo.geocode("1600 Pennsylvania Ave NW, Washington DC", addressdetails=True)
geo.reverse((38.8977, -77.0365))
Endpoint map
| Nominatim | Mailwoman | Notes |
|---|---|---|
GET /search | GET /search | free-text q and the structured fields |
GET /reverse | GET /reverse | lat / lon, point-in-polygon over the same admin data |
GET /lookup | 501 | Nominatim looks up by OSMOpenStreetMap (OSM). A community-curated global map database (ODbL-licensed) with addr:* tagged features and place hierarchies. A secondary corpus source and a source of street names. id; Mailwoman is WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations./Overture-keyed, so there are no OSMOpenStreetMap (OSM). A community-curated global map database (ODbL-licensed) with addr:* tagged features and place hierarchies. A secondary corpus source and a source of street names. ids to look up |
GET /status | GET /status | { status: 0, message: "OK" } |
ParametersparameterA single learned number inside a model — one weight or bias. Mailwoman's encoder has roughly 30 million of them; training is the search for good values. honored: q, the structured set (street, city, county, state, country,
postalcode), countrycodes, limit, viewbox, bounded, addressdetails, accept-language, and
format — jsonv2 (the default), json, or geojson (a GeoJSON FeatureCollection; coordinate in
geometry, boundingbox in bbox, the rest in properties). Long-tail params Nominatim has and
Mailwoman ignores: extratags, namedetails, dedupe, polygon_text/_svg/_kml, exclude_place_ids.
What's different
- Richer results: annotations. Every result carries an
annotationsblock — coordinate formats (DMS, MGRS, geohash, Maidenhead, Mercator), qibla bearing, sun times, the countrycountryThe top-level address component (an ISO country). Closed-vocabulary, so it is best handled by a deterministic matcher feeding a proposal rather than a retrained model head. flag, calling code, and currency, plus the IANA timezone with its current (DST-correct) offset and, where the data bundles are present, the UN/LOCODE and EU NUTS codes. Nominatim returns none of these. It's the same block OpenCage charges for. - Ids. Nominatim returns
osm_id/osm_type. Mailwoman resolves over Who's On FirstWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. and Overture, so the id scheme is ours; aplace_idis always present and stable for a given result. - Attribution. The
licencefield names the data sources (Who's On FirstWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations., Overture, OpenAddressesOpenAddresses (OA). A global open aggregation of address points collected from many official sources. A primary source of component-supervised training data outside proprietary registries., TIGERTIGERThe US Census Topologically Integrated Geographic Encoding and Referencing database. Used as a corpus source for street-segment data.) rather than OSMOpenStreetMap (OSM). A community-curated global map database (ODbL-licensed) with addr:* tagged features and place hierarchies. A secondary corpus source and a source of street names..
What's missing
- Coordinate precisionprecisionOf the spans the model labeled as a given tag, the fraction it got right. High precision means few false positives. Paired with recall to compute F1. varies by coveragecoverageThe fraction of a population or region for which a data source has real, non-placeholder entries — e.g. 47% rooftop coverage on Texas addresses. Distinct from accuracy on the rows that are present.. Where the address-point and streetstreetThe named linear feature along which house numbers are ordered. Decomposes into a name plus street affixes; one of the Tier 2 fine labels. shardsshardA partial output file of the corpus build, written in Parquet format. The training pipeline streams shards row by row. reach,
/searchreturns the rooftoprooftopGeocoding precision at the building or parcel level — coordinates within a few metres — the highest tier of the geocode cascade. Sourced from address-point and situs data. or an interpolated point —1600 Pennsylvania Avenue NWresolves to the building, withaddressdetailsdown tohouse_numberandroad. Where they don't, you get the admin centroid: the right place, not the right doorstep. Theaddressdetailsalways reflect what was parsed. - Bare ambiguous names can still collide. The worldwide gazetteergazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture. resolves international cities by
population-weighted ranking, so
Vienna, Austria,Sydney, andTirana, Albaniaall land in the right place — coveragecoverageThe fraction of a population or region for which a data source has real, non-placeholder entries — e.g. 47% rooftop coverage on Texas addresses. Distinct from accuracy on the rows that are present. now spansspanA contiguous range of characters or tokens in the input string, tagged with an address component type (street, locality, postcode, etc.). Parsed addresses are represented as collections of spans, possibly nested in a tree. the long tail of countries that used to return nothing. Where a US namesake outweighs the place you meant, a bare query can still resolve to the American twin;countrycodesforces the right one (?q=Sydney&countrycodes=au). Teaching the coarse countrycountryThe top-level address component (an ISO country). Closed-vocabulary, so it is best handled by a deterministic matcher feeding a proposal rather than a retrained model head. router to emit a countrycountryThe top-level address component (an ISO country). Closed-vocabulary, so it is best handled by a deterministic matcher feeding a proposal rather than a retrained model head. prior for those bare cases is active work (#822); an exonym likeWien/Viennaneeds the modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.', not the gazetteergazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture..
See how Mailwoman compares for the capability matrix across Nominatim, Photon, OpenCage, PeliasPeliasAn open-source geocoder, Mailwoman's spiritual predecessor., and libpostallibpostalAn open-source C address parser used by Pelias. Mailwoman's rule-based v0 and neural classifier supersede it. — including the two rows the hosted services can't check.