# Nominatim: self-hosted geocoding on OpenStreetMap data

> Nominatim turns OpenStreetMap data into a searchable geocoder and a reverse geocoder you run yourself. It is a PostgreSQL-backed Python stack, not a hosted API, and the import step is the part that decides whether it fits your project.

**osm-search/Nominatim** — Open Source search based on OpenStreetMap data

- Repository: https://github.com/osm-search/Nominatim
- Website: https://nominatim.org
- Stars: 4,506 · Forks: 861
- Language: Python
- License: GPL-3.0
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/osm-search-nominatim

## What Nominatim solves, and for whom

Nominatim is a geocoder built on OpenStreetMap data. Given a free-text query such as a street name with a house number and a city, it returns coordinates. Given a pair of coordinates, it returns an address. The README describes both directions plainly: search OSM data by name and address, and generate synthetic addresses of OSM points. The public instance at nominatim.openstreetmap.org runs the same software, and the OpenStreetMap home page search box uses Nominatim as one of its sources.

The audience is narrower than the public site suggests. Nominatim is for teams that want geocoding results they can inspect, tune and reproduce, and that are willing to run a PostgreSQL database and import OpenStreetMap extracts themselves. If you only need a few thousand lookups a month and do not care which dataset answers them, the hosted instance or a commercial geocoder will be cheaper in engineering time. The moment you need to control the data vintage, filter which OSM tags are searchable, or keep queries off someone else's servers, the calculus changes.

## How the geocoder is put together

The repository layout shows the split clearly. The Python source lives under src/, the osm2pgsql Lua configuration under lib-lua/, and SQL helpers under lib-sql/. Nominatim is not a single service with an embedded index. It is an import pipeline plus a query layer over PostgreSQL.

The import runs through the nominatim command-line tool, which the README shows as nominatim import --osm-file <your planet file>. That step reads an OSM extract and writes it into the database. The Lua files under lib-lua/ are the osm2pgsql configuration, which is where the mapping from OSM tags to searchable columns is defined. The README notes those Lua files are released under Apache License 2.0, separate from the Python code.

Serving is a separate concern. The README's quick start installs falcon and uvicorn into the virtualenv and then runs nominatim serve. The pyproject.toml lists falcon, starlette and uvicorn in a serve dependency group, and SQLAlchemy with asyncio plus psycopg in the runtime group. So the query path is an async Python web layer on top of PostgreSQL, not a static file lookup. Reverse geocoding and forward search both go through that layer.

The packaging directory holds two installable pieces, nominatim-api and nominatim-db, and the Makefile builds them separately with python3 -m build packaging/nominatim-db and python3 -m build packaging/nominatim-api. That separation matters if you want the query library without the import machinery, or the other way around.

## Installing Nominatim and running a first import

The README gives a four-step quick summary. First clone the repository and fetch the country grid, which the import uses for country assignment. The wget target is Nominatim/data/country_osm_grid.sql.gz, and the file is downloaded from nominatim.org rather than from the git repository.

```bash
git clone https://github.com/osm-search/Nominatim.git
wget -O Nominatim/data/country_osm_grid.sql.gz https://nominatim.org/data/country_grid.sql.gz
```

Second, create a virtualenv and install the two packages from the packaging directory. Note that the README installs them from the local checkout, not from PyPI.

```bash
python3 -m venv nominatim-venv
./nominatim-venv/bin/pip install packaging/nominatim-{api,db}
```

Third, create a project directory, change into it, and run the import against your OSM file. The README pipes output through tee into setup.log, which is worth keeping because the import is long and the log is the only record of what happened.

```bash
mkdir nominatim-project
cd nominatim-project
../nominatim-venv/bin/nominatim import --osm-file <your planet file> 2>&1 | tee setup.log
```

Fourth, install a web server and start serving. The README installs uvicorn and falcon at this point, after the import, and then runs nominatim serve from inside the project directory.

```bash
./nominatim-venv/bin/pip install uvicorn falcon
../nominatim-venv/bin/nominatim serve
```

What you should see is the import writing progress into setup.log and, once serve is running, an HTTP endpoint answering search and reverse requests. The README does not print the default port in the quick summary, so check the installation documentation at nominatim.org before pointing a client at it. The README also points to a Troubleshooting and FAQ section for the release, which is where import failures and database version problems are covered.

## The import is the real cost, and the real constraint

Nothing in the README hides this, but it is easy to skim past: step three takes a planet file. A full planet import is a disk-bound, hours-long operation against PostgreSQL, and the README's own instructions send the output to a log file rather than to the terminal, which tells you the authors expect it to run for a while. If your use case is a city or a country, you should import an extract of that region rather than the planet, and the README's --osm-file argument accepts whatever file you point it at.

The second constraint is update cost. The README documents import and serve but does not document an update or replication workflow in the quick summary. Anyone running this in production needs to read the administration documentation for how the database is kept current, because a geocoder with stale data silently returns wrong answers rather than errors. This is the point where a hosted service is genuinely easier: it absorbs the refresh problem for you.

Third, the dependency surface is not small. pyproject.toml pins runtime dependencies including PyICU, mwparserfromhell, SQLAlchemy with asyncio, psycopg, psutil and jinja2, with an explicit exclusion of psycopg 3.3.0. PyICU in particular is a system-library binding, so a plain pip install can fail on a machine without the underlying ICU development packages. The README does not walk through those system prerequisites in the quick summary; the full installation page does.

Finally, Nominatim is a geocoder, not a routing engine and not a tile server. It answers where something is and what is at a coordinate. If you need turn-by-turn directions or map rendering, this is the wrong component, even though all three consume OpenStreetMap data.

## Nominatim against the hosted geocoding APIs

The obvious alternative is a hosted geocoding service, whether that is the public nominatim.openstreetmap.org instance or a commercial provider. The difference is not accuracy in the abstract; it is who owns the data pipeline. A hosted API gives you an endpoint and an API key and takes on import, updates, uptime and capacity. You get no control over which OSM snapshot is loaded, no ability to change how tags map to searchable fields, and no way to keep queries inside your own network.

Running Nominatim yourself inverts every one of those. You choose the extract, you decide when to re-import, you can edit the Lua configuration to change what is indexed, and queries never leave your infrastructure. You pay for it with PostgreSQL administration and with the import time.

There is also a middle path worth naming: the Python packages under packaging/ can be installed without running the full server, and the README's own install line pulls nominatim-api and nominatim-db together. If you want the query layer against your own database rather than the HTTP service, that is the route to investigate. The README does not spell out that use case, so read the library documentation before assuming it is supported as a stable public interface.

## Licence, maintenance and upgrade cost

The licence situation is split, and the README states it directly. The Python source is GPL version 3 or later. The Lua configuration files for osm2pgsql are Apache License 2.0. All other files are GPLv2. That means the parts you are most likely to modify for your own tag mapping sit under a permissive licence, while the Python code you would extend or embed is copyleft. If you plan to link Nominatim's Python code into a proprietary product, that distinction is the one to take to a lawyer. This article does not give legal advice.

On maintenance: the repository is not archived, and the last push was on 2026-09-16. The most recent tagged release is v5.3.2 from 2026-04-19, following v5.3.1 on 2026-04-10 and v5.3.0 on 2026-04-03. The pattern suggests a stable line with patch releases rather than constant churn.

Upgrade cost is dominated by the database, not the Python packages. A new release can change the schema or the import pipeline, and that generally means a re-import rather than an in-place pip upgrade. The ChangeLog file at the repository root and the release documentation at nominatim.org are where the migration steps live. Budget for a parallel database and a re-import window, not for a five-minute package bump.

## Conclusion

Adopt Nominatim when you need geocoding over OSM data that you control, can afford the disk and import time, and are willing to run PostgreSQL next to it. Do not adopt it when a hosted geocoding API with a per-request key is enough, or when your data is not OpenStreetMap. Before committing, verify the size of the planet file you intend to import, the PostgreSQL version your distribution ships, and whether your use case needs the web API at all or only the command-line import.

## FAQ

### What is Nominatim used for?

It searches OpenStreetMap data by name and address, and it generates synthetic addresses for OSM points. The public instance at nominatim.openstreetmap.org runs it, and the OpenStreetMap home page search box uses it as one of its sources.

### Is Nominatim free?

The software is open source. The Python source is under GPL version 3 or later, the osm2pgsql Lua configuration files are under Apache License 2.0, and all other files are under GPLv2. Running it yourself still costs whatever the hardware and PostgreSQL administration cost.

### How do I install Nominatim?

The README's quick summary clones the repository, downloads the country grid, creates a Python virtualenv, installs the nominatim-api and nominatim-db packages from the packaging directory, imports an OSM file with nominatim import, and starts the server with nominatim serve after installing uvicorn and falcon. Detailed instructions for the current release are on nominatim.org.

### How do I use the Nominatim API?

The README's quick start runs nominatim serve after installing uvicorn and falcon into the virtualenv, which exposes the search and reverse geocoding endpoints. The quick summary does not state the default port, so check the installation and API documentation at nominatim.org.

## Sources

- [License: GPL-3.0](https://github.com/osm-search/Nominatim/blob/master/LICENSE)
- [osm-search/Nominatim on GitHub](https://github.com/osm-search/Nominatim)
- [Project website](https://nominatim.org)
- [README](https://github.com/osm-search/Nominatim/blob/master/README.md)
- [Releases](https://github.com/osm-search/Nominatim/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/osm-search-nominatim
