Skip to main content

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

NominatimMailwomanNotes
GET /searchGET /searchfree-text q and the structured fields
GET /reverseGET /reverselat / lon, point-in-polygon over the same admin data
GET /lookup501Nominatim 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 /statusGET /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 formatjsonv2 (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 annotations block — 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; a place_id is always present and stable for a given result.
  • Attribution. The licence field 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, /search returns 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 NW resolves to the building, with addressdetails down to house_number and road. Where they don't, you get the admin centroid: the right place, not the right doorstep. The addressdetails always 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, and Tirana, Albania all 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; countrycodes forces 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 like Wien/Vienna needs 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.