Deploy Nominatim
OpenStreetMap geocoder turning addresses into coordinates and back
nominatim
Just deployed
/var/lib/postgresql/16/main
Deploy and Host Nominatim on Railway
Nominatim is the geocoder behind search on openstreetmap.org. It turns a written address into coordinates and a pair of coordinates back into an address, using nothing but OpenStreetMap data and a PostgreSQL database you control. Mapping teams, logistics platforms and anyone tired of per-request billing from Google or Mapbox self-host Nominatim for unmetered geocoding with no API quota and no user addresses leaving their infrastructure.
Deploy Nominatim on Railway as a single nominatim service. It packages the Nominatim 5.3 API, the OSM importer and a PostgreSQL 16 database with PostGIS in one container, with the cluster on a Railway volume at /var/lib/postgresql/16/main. A Caddy front door serves nominatim-ui at /ui/, proxies every API route, and protects both with HTTP basic auth, because Nominatim ships no authentication of its own. The first deployment imports the extract named by PBF_URL; every later one finds the finished database on the volume and serves in seconds.

Getting Started with Nominatim on Railway
The template defaults to the Monaco extract, so the first import finishes in under a minute — change PBF_URL before deploying if you want another region. The logs show the download, osm2pgsql loading it, the index ranks building, then Starting Gunicorn. Open the deployed URL: the browser asks for API_USERNAME and API_PASSWORD, then redirects to /ui/, the nominatim-ui search page. Type a place name that exists in your extract and press Search — a result card and a map marker confirm the import worked.
Click details on any result for the full OpenStreetMap record: every localised name, the address breakdown, the search and address ranks, and the computed postcode. The Reverse tab turns a coordinate pair into the nearest addressable feature. The same answers come back as JSON from /search?q=...&format=jsonv2 and /reverse?lat=...&lon=...&format=jsonv2, which is what your application calls. /status is left unauthenticated for health checks and monitoring; it queries the database and reports the software version and the age of your data.



About Hosting Nominatim
Nominatim is a search engine built for OpenStreetMap's data model. Importing an extract is not a copy: osm2pgsql loads the raw OSM objects, then Nominatim derives a place hierarchy — country, state, county, city, suburb, street, house number — computes address interpolations, normalises names through an ICU tokenizer, and builds the indexes that let a free-text query resolve to one building.
Key capabilities:
- Forward geocoding, structured address search, and reverse geocoding from coordinates
- Polygons, bounding boxes, address breakdowns and per-language name variants
- Continuous replication of OpenStreetMap's own diffs, so your data stays current
- JSON, GeoJSON, GeoCodeJSON and XML output, compatible with existing Nominatim clients
The service holds three cooperating parts. PostgreSQL 16 with PostGIS stores the place table and its indexes on the volume. The Nominatim API runs under Gunicorn with uvicorn workers sized from the container's CPU quota. Caddy sits in front, serving nominatim-ui, proxying the API, and applying basic auth so the deployment is not an open geocoder for strangers. One caveat worth knowing: the optional Wikipedia and Wikidata importance tables are not imported, so forward search may prefer a less prominent match among identically named places. Reverse geocoding is unaffected.
Why Deploy Nominatim on Railway
Railway removes the parts of self-hosting Nominatim that go wrong:
- One click provisions the container, the volume and the public domain
- The import runs on first boot and is skipped on every deploy afterwards
- PostgreSQL memory and worker counts are derived from your plan's limits
- The health check waits out a long first import instead of failing the deploy
- Basic auth and TLS are in place before the service is reachable
Common Use Cases
- Address autocomplete and validation in a checkout or onboarding form, with no per-lookup fees
- Reverse geocoding fleet, delivery or asset telemetry into street addresses
- Batch-geocoding a customer database privacy rules forbid sending to a third party
- Backing an internal mapping tool where usage spikes make a metered geocoder unpredictable
Dependencies for Nominatim
mediagis/nominatim:5.3— the project's own container: Nominatim 5.3.2, PostgreSQL 16, PostGIS,osm2pgsqlnominatim-ui3.12.0 — the official web frontend, served from/ui/caddy:2— the front door providing basic auth and static file serving- A Railway volume — where the PostgreSQL cluster and the imported data live
Environment Variables Reference
| Variable | Purpose |
|---|---|
PBF_URL | The OpenStreetMap extract to import on first boot |
API_USERNAME / API_PASSWORD | HTTP basic auth credentials for the UI and API |
API_AUTH | Set to disabled to serve anonymously |
NOMINATIM_PASSWORD | Password for the internal PostgreSQL role |
REPLICATION_URL | The -updates/ directory beside your extract |
UPDATE_MODE | continuous, once, catch-up, or unset to freeze the data |
THREADS / GUNICORN_WORKERS | Import threads and API workers; default to the CPU quota |
REVERSE_ONLY | Skip the search index for a smaller, reverse-only database |
IMPORT_STYLE | full, street, address or admin — detail versus import speed |
Deployment Dependencies
- Source repository: https://github.com/gridalpha/nominatim-railway
- Upstream project: https://github.com/osm-search/Nominatim
- Container project: https://github.com/mediagis/nominatim-docker
- Documentation: https://nominatim.org/release-docs/latest/
- Extracts: https://download.geofabrik.de/
Hardware Requirements for Self-Hosting Nominatim
Requirements scale with the extract, not with traffic. The table covers a city or small-country extract.
| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 2 vCPU | 4–8 vCPU (import is parallel) |
| RAM | 2 GB | 8 GB |
| Storage | 5 GB volume | ~10× the .osm.pbf size |
| Runtime | PostgreSQL 16 + PostGIS, Python 3 | same |
A country extract of a few hundred megabytes imports in tens of minutes and wants a volume in the tens of gigabytes. A whole-planet import needs roughly 1 TB of fast SSD.
Self-Hosting Nominatim
To change region, point PBF_URL at any Geofabrik extract and redeploy onto an empty volume. For Great Britain:
PBF_URL=https://download.geofabrik.de/europe/great-britain-latest.osm.pbf
REPLICATION_URL=https://download.geofabrik.de/europe/great-britain-updates/
UPDATE_MODE=continuous
Query it from any HTTP client. The following uses curl with the basic-auth credentials:
curl -u "$API_USERNAME:$API_PASSWORD" \
"https://your-app.up.railway.app/search?q=10+Downing+Street&format=jsonv2&limit=1"
curl -u "$API_USERNAME:$API_PASSWORD" \
"https://your-app.up.railway.app/reverse?lat=51.5034&lon=-0.1276&format=jsonv2"
How Much Does Nominatim Cost to Self-Host?
Nominatim is free and open source under GPL-2.0, and OpenStreetMap data is free under the ODbL. There is no paid tier, no seat count and no request quota — the only cost is the infrastructure, billed by Railway for the container's CPU, memory and volume. That is the appeal next to Google Geocoding, Mapbox or LocationIQ, which charge per request once a modest free allowance is gone. Attribution to OpenStreetMap contributors is required when you display results.
FAQ
What is Nominatim? Nominatim is the open-source geocoding engine behind OpenStreetMap's search box. It converts addresses and place names into coordinates, and coordinates back into addresses, from an OpenStreetMap extract loaded into PostgreSQL.
What does this Railway template deploy?
One service running Nominatim 5.3, PostgreSQL 16 with PostGIS and the nominatim-ui frontend, with a volume for the database and a Caddy front door adding HTTP basic auth. It imports the extract named by PBF_URL on first boot.
Why does Nominatim need a volume instead of a managed database? Nominatim's importer initialises its own PostgreSQL cluster, installs PostGIS and a large body of PL/pgSQL, and tunes the server for a bulk load. Railway's managed Postgres has neither PostGIS nor those settings, so the database runs inside the service and persists on the volume.
How do I geocode a different country or region?
Point PBF_URL at another Geofabrik extract, set REPLICATION_URL to the matching -updates/ directory, and deploy onto a fresh volume — the import only runs when the volume holds no database.
How do I keep the OpenStreetMap data up to date?
Leave UPDATE_MODE=continuous and REPLICATION_URL set. A background process applies OpenStreetMap's published diffs on the REPLICATION_UPDATE_INTERVAL schedule, and /status reports the newest data applied.
Can I expose the API without a password?
Yes — set API_AUTH=disabled and redeploy. Do that only if you mean to run a public geocoder, since an open endpoint is usable by anyone who finds the URL.
Template Content
nominatim
gridalpha/nominatim-railway