BRouter: offline OSM routing built on rd5 segments and text profiles
configurable OSM offline router with elevation awareness, Java + Android
At a glance
- What is it?
- BRouter is a Java and Android offline router for OpenStreetMap data with elevation awareness, aimed at bicycle and energy based car routing, where the configuration surface is a set of text profiles rather than a settings screen. Adoption means generating or downloading rd5 segment files, building with Gradle and deciding how to run the HTTP server.
- Who is it for?
- Adopt BRouter when you need routing that works with no network, that weights roads by gradient and energy for bicycles, or that you intend to tune yourself through profile files rather than through a consumer app, and when you are willing to generate or download rd5 data.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 25 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A router that reads OpenStreetMap and weights the gradient
BRouter is described in the README as a configurable OSM offline router with elevation awareness, written in Java with an Android app. The design goal is multi-modal routing with a particular emphasis on bicycle routing and energy based car routing, which is the part that separates it from a general purpose map router.
Elevation awareness is the reason the configuration exists. Instead of choosing between a shortest path and a fastest path, a profile can account for gradient, so a route can favour a climb-free path or penalise a steep one, and for cars it can weigh energy use. The README notes that the repository holds examples of BRouter profiles for many transportation modes, and that most of them can be customised by setting variables in the first global context of the profile files.
That last point shapes how you use the tool. BRouter is not a routing app with a preferences screen, it is a routing engine whose behaviour is decided by a text profile, and the Android application is one consumer of that engine rather than the product itself.
Routing data lives in 5 by 5 degree rd5 segments
The data model is the part you have to understand before anything else works. Routing data files are organised as 5 by 5 degree squares, and the filename carries the south-west corner of the square. The README gives two concrete examples: routing near West48/North37 requires W50_N35.rd5, and routing near East7/North47 requires E5_N45.rd5.
These files are called segments across the project. They are generated from OpenStreetMap data and stored in a custom binary format called rd5, which the README says exists for improved efficiency of BRouter routing.
Two routes to obtaining them are offered. Segment files for the whole planet are generated weekly and published at brouter.de/brouter/segments4/, and you can download one or more covering the area you care about into the misc/segments4 directory. Alternatively you can generate the files yourself from a planet dump of OpenStreetMap data or from a GeoFabrik extract, with the procedure described in docs/developers/build_segments.md. The choice matters in practice: a self generated file lets you control the area and the update cycle, while a download costs nothing but ties you to the weekly build of someone else's data.
Building with Gradle, with or without the Android app
Compilation goes through the Gradle wrapper checked into the repository. If you want the Android application included, the Android SDK path has to be set first in a file called local.properties in the main folder:
sdk.dir=<your/android/sdk/path>With that in place the whole project, including the app, is built with:
./gradlew clean buildBuilding the server without the Android application avoids the SDK requirement entirely:
./gradlew clean build -x :brouter-routing-app:buildTwo packaging targets matter for deployment. The fatJar target bundles the server and map creator with all dependent classes into a single JAR:
./gradlew clean build fatJar # places JAR file in brouter-server/build/libs/And the distribution target assembles a ZIP with readmes, profiles, the APK and the JAR:
./gradlew distZip # places ZIP file in brouter-server/build/distributions/The source layout follows the same split. At the top level you find brouter-core, brouter-codec, brouter-expressions, brouter-map-creator, brouter-mapaccess, brouter-util, brouter-routing-app and brouter-server, which is a modular design where the routing algorithm, the data formats and the user facing pieces are separable.
The HTTP server and its eight field request log
The server is meant to be run from helper scripts in misc/scripts/standalone that spawn it for various platforms. On Linux and Mac OS, and on Windows using Bash, that is the server.sh script inside misc/scripts/standalone. The container image starts the same script, as its command shows:
CMD ["/app/server.sh"]On Windows using CMD the equivalent is the server.cmd script in the same directory. The API endpoints the server exposes are documented in the source file brouter-server/src/main/java/btools/server/request/ServerHandler.java, which is where to look if you are writing a client rather than using the app.
The operational detail worth knowing is the log format. The server emits a line per routing request on stdout, made of eight whitespace separated fields: a timestamp in ISO8601 format, the current server session count as an integer between 1 and 999 or the word new when a new IP address is detected, the IP address prefixed by ip=, the request duration in milliseconds prefixed by ms=, a divider, the HTTP request method, the request URL and the request version. A typical pair of lines looks like this:
2024-05-14T21:11:26.499+02:00 new ip=127.0.0.1 ms=189 -> GET /brouter?lonlats=13.377485,52.516247%7C13.351221,52.515004&profile=trekking&alternativeidx=0&format=geojson HTTP/1.1
2024-05-14T21:11:33.229+02:00 1 ip=127.0.0.1 ms=65 -> GET /brouter?lonlats=13.377485,52.516247%7C13.351221,52.515004&profile=trekking&alternativeidx=0&format=geojson HTTP/1.1Because the URL is logged verbatim, a query string containing coordinates ends up in your logs, so treat that stdout stream as data you may need to filter.
Docker packaging, four environment variables and one exposed port
A ready made image for amd64 and arm64 is published at ghcr.io/abrensch/brouter. The tag latest points to the newest release, a tag such as v1.7.10 points at that specific release, and nightly tracks the daily build of master. The container runs as user 1000 and starts server.sh, which reads its configuration from environment variables.
The image itself is a two stage Dockerfile. The build stage runs on the build host for every target platform, because the jar is architecture independent, using eclipse-temurin:17-jdk-jammy, and only the runtime stage runs per platform on eclipse-temurin:17-jre-jammy. The runtime stage creates a brouter user with uid 1000, makes the application, segments and custom profiles directories writable by it, copies the all dependencies jar to /app/brouter.jar and the server script to /app/server.sh, and sets the paths as environment variables:
ENV CLASSPATH=/app/brouter.jar \
SEGMENTSPATH=/segments4 \
PROFILESPATH=/profiles2 \
CUSTOMPROFILESPATH=/customprofilesThe documented variables are JAVA_OPTS, whose default is -Xmx128M -Xms128M -Xmn8M -DmaxRunningTime=300 -DuseRFCMimeType=false and which also carries the request timeout, MAXTHREADS defaulting to 1 and counting how many requests the server handles at once, PORT defaulting to 17777, and BINDADDRESS defaulting to all interfaces. That single threaded default is the number to watch. A server handling public traffic needs MAXTHREADS raised, and the 128M heap default is sized for a small instance.
Profiles are the configuration, and they are plain text
Every routing decision in BRouter comes from a profile, and profiles are text files with variables in a first global context. The repository ships examples for many transportation modes, and the Docker image copies them into /profiles2 while pointing CUSTOMPROFILESPATH at a /customprofiles directory that the container creates, so you can mount your own profiles there without rebuilding the image.
There is a helper script for the common case. misc/scripts/generate_profile_variants.sh is there to quickly generate variants based on the default profiles and create a default set covering most of the basic use cases. That approach works because the default profiles differ mainly in the values of a few variables, so a variant is a small edit rather than a new file.
For anything beyond that, docs/developers/profile_developers_guide.md is described as an in depth guide on profile edition and customization, and the expression layer has its own module in the source tree, brouter-expressions. The upshot is that profile work is a scripting task, not a GUI task, which is exactly what you want if you are encoding an organisation specific routing policy and exactly what you do not want if you expected a routing preference panel.
Android, Locus and OSMAnd: three ways in
On Android there are two installation routes and two integration routes. The app can be installed from F-Droid or from the Google Play Store under the package btools.routingapp, and it can also be built from source. Detailed documentation for the Android app lives in docs/users/android_quickstart.md.
The more interesting option is to use BRouter as the offline routing engine inside another app. The README calls the Locus Map integration the most featureful and maintained solution for using BRouter on an Android device, with setup documented on the Locus site, and it also points out that BRouter can serve as the offline routing engine for OSMAnd, with the instructions in docs/users/osmand.md.
That distinction matters when you evaluate the project. The BRouter Android app is one consumer of the engine, and the engine can equally sit behind Locus Map or OSMAnd, which are described as the current alternatives. If your users already live in one of those apps, adding BRouter behind it is a smaller change than replacing their navigation software with the BRouter app.
A 1.7.x release line, a Java 17 runtime and an MIT licence
The project is alive but the releases come in a slow, irregular pattern. The recent tags are v1.7.10 from 2026-07-17, v1.7.9 from 2026-04-20 and v1.7.8 from 2025-07-12, and the last push to the repository was on 2026-09-28. So the patch level moves several times a year, while about nine months passed between v1.7.8 and v1.7.9.
The runtime target is fixed and visible in the Dockerfile, which builds on eclipse-temurin 17 and runs on the matching JRE image. Both the build stage and the runtime stage therefore need Java 17 available, and the native image published to ghcr.io is built for amd64 and arm64, which matters if you deploy on a Raspberry Pi or an ARM cloud instance.
Licensing is MIT, which is permissive: commercial use and modification are allowed, and the only obligation is retaining the notice. The practical cost of adoption is therefore operational rather than legal. You are taking on the segment data pipeline, the profile tuning and the patching of a project whose release cadence is roughly quarterly, and the upgrade path is a rebuild of your own data and profiles rather than a package manager update.
Editorial conclusion
Adopt BRouter when you need routing that works with no network, that weights roads by gradient and energy for bicycles, or that you intend to tune yourself through profile files rather than through a consumer app, and when you are willing to generate or download rd5 data. Do not adopt it if you need turn by turn navigation with a polished mobile interface, since the Android app is a front end over a routing engine and the Locus and OSMAnd integrations are documented separately. Verify first that the profile you need exists for your transport mode, that segment files cover the area you will route in, and that the container port and MAXTHREADS values suit your traffic, since the default single threaded server and the 17777 listen port are what the shipped configuration gives you.
Frequently asked questions
What is BRouter used for?
BRouter is an offline router for OpenStreetMap data with elevation awareness, designed to be multi-modal with an emphasis on bicycle routing and energy based car routing. Routing behaviour is defined by text profiles rather than application settings.
How do I get routing data for BRouter?
Data comes as rd5 segment files covering 5 by 5 degree squares, with the filename carrying the south-west corner, so routing near West48/North37 needs W50_N35.rd5. You can download weekly planet builds from brouter.de/brouter/segments4/ into the misc/segments4 directory, or generate files from an OpenStreetMap planet dump or a GeoFabrik extract as described in docs/developers/build_segments.md.
How do I run the BRouter server?
Helper scripts are provided in misc/scripts/standalone. On Linux, Mac OS and Windows with Bash, run ./misc/scripts/standalone/server.sh, and on Windows with CMD use misc\scripts\standalone\server.cmd. The API endpoints are documented in brouter-server/src/main/java/btools/server/request/ServerHandler.java.
How does the BRouter Docker image work?
Images for amd64 and arm64 are published at ghcr.io/abrensch/brouter, where latest tracks the newest release, a tag such as v1.7.10 tracks that release and nightly tracks the daily build of master. The container runs as user 1000 and reads JAVA_OPTS, MAXTHREADS, PORT, BINDADDRESS and the segment and profile paths from environment variables, with PORT defaulting to 17777.
Can BRouter be used inside Locus Map or OSMAnd?
Yes. The README describes using BRouter as the offline routing engine for Locus Map, calling it the most featureful and maintained solution for that purpose, and also for OSMAnd. Setup notes live in the Locus documentation and in docs/users/osmand.md.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/abrensch-brouter)