# OSRM Backend: Self-Hosted Routing on OpenStreetMap Data

> OSRM Backend is a C++ routing engine that turns OpenStreetMap extracts into a self-hosted HTTP routing service. It is fast and well documented, but preprocessing is a batch job with a real time cost.

**Project-OSRM/osrm-backend** — Open Source Routing Machine - C++ backend

- Repository: https://github.com/Project-OSRM/osrm-backend
- Website: https://discord.gg/CpWzBC9G7Z
- Stars: 8,117 · Forks: 3,972
- Language: C++
- License: BSD-2-Clause
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/project-osrm-osrm-backend

## What OSRM Backend Solves, and Who It Is For

The README describes OSRM as a "High performance routing engine written in C++ designed to run on OpenStreetMap data." That sentence carries the whole positioning. The project does not ship map data. You bring an OpenStreetMap extract, typically a `.osm.pbf` file from a provider such as Geofabrik, and OSRM turns it into a routable graph you query over HTTP.

The services exposed are Nearest, Route, Table, Match, Trip and Tile. Nearest snaps a coordinate to the street network. Route finds the fastest path between coordinates. Table computes durations or distances between all pairs in a set of coordinates. Match snaps a noisy GPS trace to the road network. Trip solves the Traveling Salesman Problem with a greedy heuristic. Tile emits Mapbox Vector Tiles with routing metadata.

That list tells you who this is for. A delivery company that wants to compute a duration matrix for its own fleet. A mobile app team that needs map matching for recorded traces. A data team that wants isochrone or tile output without paying per request. It is not for someone who wants a routing answer without running a server. The demo server at map.project-osrm.org exists for evaluation, and the README presents it as a way to "quickly try OSRM", not as production infrastructure.

The repository topics include isochrones, map-matching and traveling-salesman, which matches the service list. The C++ implementation and the HTTP API are the two surfaces the README names first; the NodeJS wrapper and the C++ library interface are also listed.

## The MLD and CH Preprocessing Pipelines

OSRM does not answer queries directly from the `.osm.pbf` file. It runs a preprocessing pipeline first, and the README documents two of them: Contraction Hierarchies (CH) and Multi-Level Dijkstra (MLD).

MLD is the default recommendation. The pipeline is three commands: `osrm-extract`, then `osrm-partition`, then `osrm-customize`. The extract step reads the OSM file and a Lua profile, and produces an edge-expanded graph representation. The partition step divides that graph. The customize step prepares the weights the query engine uses.

CH collapses those last two steps into a single `osrm-contract` call, and you then start the server with `--algorithm ch`. The README gives a concrete reason to prefer MLD: it says to use MLD by default "except for special use cases such as very large distance matrices where CH is still a better fit for the time being." That is a useful boundary to remember, and it is the kind of statement that usually gets lost when people copy a Docker command without reading the surrounding paragraph.

The preprocessing is where the time goes. The README notes that the process "can take a long time to complete with little changes on the terminal output" and gives one data point: a Mexico OSM file of 550.7MB took around 30 minutes to finish extraction and generate the edge-expanded graph representation. That number is the project's own, not a benchmark run here, and it covers extraction only. Partition and customize are separate invocations that also take time.

One detail trips people up. There is no single `berlin-latest.osrm` file. The README states that the path is a base path referring to a set of `berlin-latest.osrm.*` files, and that the `.osrm` suffix can be omitted entirely.

## Installing OSRM Backend with Docker and Making a First Route Request

The README calls Docker "the easiest and quickest way to setup your own routing engine". The images are based on Debian Linux and published in the GitHub Container Registry as `ghcr.io/project-osrm/osrm-backend`. Older backend versions are on Docker Hub.

Start by downloading an extract. The README uses a Berlin extract from Geofabrik:

```bash
wget http://download.geofabrik.de/europe/germany/berlin-latest.osm.pbf
```

Then preprocess it with the car profile. The `-v "${PWD}:/data"` flag mounts the current working directory at `/data` inside the container, so the host file appears as `/data/berlin-latest.osm.pbf`.

```bash
docker run -t -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-extract -p /opt/car.lua /data/berlin-latest.osm.pbf || echo "osrm-extract failed"
```

The two remaining MLD steps operate on the base path, not on a single file:

```bash
docker run -t -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-partition /data/berlin-latest.osrm || echo "osrm-partition failed"
docker run -t -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-customize /data/berlin-latest.osrm || echo "osrm-customize failed"
```

Now start the server on port 5000 and query it. The route URL format is `/route/v1/{profile}/{lon,lat};{lon,lat}` and the README's example adds `?steps=true` to include turn-by-turn steps.

```bash
docker run -t -i -p 5000:5000 -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-routed --algorithm mld /data/berlin-latest.osrm
curl "http://127.0.0.1:5000/route/v1/driving/13.388860,52.517037;13.385983,52.496891?steps=true"
```

If you want a map on top, the README offers a separate frontend image on port 9966:

```bash
docker run -p 9966:9966 osrm/osrm-frontend
```

If Docker reports that it cannot connect to the daemon, the README's fix is to add your user to the `docker` group with `sudo usermod -aG docker $USER`, then log out and back in. Building from source is also documented, and the README says dependencies are managed with vcpkg in manifest mode, requiring a C++20 compiler, CMake 3.29 or newer, Ninja, and some autotools packages.

## Where OSRM Backend Is the Wrong Tool

The preprocessing model is the main constraint, and it has a few consequences worth stating plainly.

First, updates are not incremental in the way an application developer might assume. To serve a new extract you rerun the pipeline and restart the server. There is no documented hot reload in the README. For a small city extract that may be fine. For a country-sized extract, the extraction step alone is measured in tens of minutes according to the README's own example, and that example is a 550.7MB file, not a planet file.

Second, the preprocessing is not a one-time cost you can amortize across profiles. The Lua profile is an input to `osrm-extract`. Changing from car to another profile means running the pipeline again, because the profile shapes the graph. The repository has a `profiles/` directory, and the README's example uses `/opt/car.lua` inside the image.

Third, the README does not document rollback. If a new extract produces a graph that behaves badly, the documented path is to keep the old files and start the server against them, which is an operational decision you have to make yourself. There is no versioned graph store described.

Fourth, if you want routing as a service with someone else operating the servers, OSRM Backend is the wrong layer. It is a backend. The README points at a demo server for trying it, but a demo server is not a support contract, and the project's support section asks for contributions of time and expertise rather than offering an SLA.

Finally, the HTTP API is the stable interface to plan around. The README lists the C++ library interface and the NodeJS wrapper as available services, but the NodeJS package is published as `@project-osrm/osrm` with `node-pre-gyp` and a fallback build script, and its `engines` field requires Node `^20.17.0 || >=22.9.0`. The Python bindings live in `pyproject.toml` under the name `osrm-bindings`, require Python 3.10 or newer, and build through scikit-build-core and nanobind. Treat all of those as build-from-source surfaces with their own toolchain expectations, not as drop-in libraries.

## How OSRM Backend Compares to a Hosted Routing API

The clearest alternative in kind is a hosted routing API, where a vendor runs the graph and you send coordinates over HTTPS. The difference is not the shape of the query. Both take a pair of coordinates and return a route. The difference is where the graph lives and who pays for keeping it current.

With a hosted API you have no `osrm-extract` step, no `.osrm.*` files on disk, no port 5000 to expose, and no extract download. You also have no control over which OpenStreetMap snapshot is loaded, no ability to supply your own Lua profile, and no way to run a Table query whose size you decide. Pricing is per request or per element, which is a different cost curve from a fixed amount of CPU and disk.

With OSRM Backend you own the snapshot. If your routing logic depends on a tag that the default car profile handles a certain way, you can change the profile and rerun the pipeline. If you need the graph to stay inside your network, it does. The cost is the pipeline: disk for the `.osm.pbf` and the generated files, CPU for extraction, partition and customize, and a restart whenever the data changes.

The README's own framing supports this reading. It points at the demo server for a quick trial and then immediately moves to Docker and self-hosting as the way to "setup your own routing engine". There is no hosted commercial tier described in the README. The support section lists GitHub Sponsors and PayPal as ways to fund the project, which is community funding, not a service offering.

A second comparison is worth drawing against writing your own shortest-path code over a road graph. OSRM's value there is the pipeline plus the query algorithms plus the profile system. Reimplementing CH or MLD and an OSM parser is a large project; the repository's `src/`, `include/` and `unit_tests/` directories show the scale of what already exists.

## Licence, Maintenance and Upgrade Cost

The licence is BSD-2-Clause, stated in `package.json` and in the `LICENSE.TXT` file at the repository root. The `pyproject.toml` for the Python bindings also references `LICENSE.TXT`. BSD-2-Clause is a permissive licence, but the obligations it carries, and how they interact with the OpenStreetMap data licence that applies to your extracts, are questions for your own legal review. Nothing here is legal advice.

The repository is not archived, and the last push was on 2026-09-13. Releases are frequent and versioned by year and month: v26.9.0 on 2026-09-01, v26.8.0 on 2026-08-01, and v26.7.3 on 2026-07-10. That cadence means upgrade cost is not zero. The container registry publishes `latest` as master compiled with the release flag, plus `latest-assertions` and `latest-debug` variants, and per-tag images with and without a `-debug` suffix. Pinning to a tag rather than `latest` is the only way to make an upgrade a decision instead of an event.

The real upgrade cost sits in the preprocessing artifacts. A new backend version may change the graph format, which means the `.osrm.*` files you generated with the previous version may need to be regenerated. The README does not state a compatibility guarantee between versions for those files. Budget for a full pipeline rerun when you move tags, and keep the previous extract and its generated files until the new server has answered real queries.

There is also a Python packaging detail with upgrade consequences. `pyproject.toml` sets `wheel.py-api = "cp312"` and `[tool.cibuildwheel]` builds `cp312-*` wheels while skipping `*musllinux*`. If your environment is not CPython 3.12 on a glibc-based image, expect to build from source.

## Conclusion

Adopt OSRM Backend if you need route, table, match or trip queries against your own OpenStreetMap extract and can accept a preprocessing step before the server starts. Do not adopt it if you need a hosted API with no infrastructure, or if you expect the graph to update continuously; the README describes a batch pipeline, and the repository does not document rollback for a bad extract. Verify first that your extract is small enough for the preprocessing time you can tolerate, and that your client can consume the HTTP API or the NodeJS wrapper rather than expecting a stable ABI.

## FAQ

### What does OSRM do?

OSRM Backend is a routing engine written in C++ that runs on OpenStreetMap data. It exposes Nearest, Route, Table, Match, Trip and Tile services over an HTTP API, a C++ library interface and a NodeJS wrapper.

### Is OSRM an API?

It is a self-hosted engine rather than a hosted API. The README lists the services as available via an HTTP API, a C++ library interface and a NodeJS wrapper, and the quick start runs an HTTP server on port 5000 that you query with curl.

### How do I set up OSRM?

The README recommends Docker as the quickest route. Download an OSM extract, run osrm-extract with a profile, then osrm-partition and osrm-customize for the MLD pipeline, and finally start osrm-routed with --algorithm mld.

### What is routing in backend?

In OSRM Backend, routing means answering queries against a preprocessed OpenStreetMap graph rather than reading the raw .osm.pbf file. The README's quick start builds that graph with osrm-extract, osrm-partition and osrm-customize before osrm-routed serves requests.

## Sources

- [License: BSD-2-Clause](https://github.com/Project-OSRM/osrm-backend/blob/master/LICENSE)
- [Project-OSRM/osrm-backend on GitHub](https://github.com/Project-OSRM/osrm-backend)
- [Project website](https://discord.gg/CpWzBC9G7Z)
- [README](https://github.com/Project-OSRM/osrm-backend/blob/master/README.md)
- [Releases](https://github.com/Project-OSRM/osrm-backend/releases)

---

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