Performant intracontinental transit routing in Rust

In 2022, I started the Headway maps project, aiming to democratize maps services by making it easy to self-host your own web maps based on OpenStreetMap data. The project was well received, but to this day it is notably missing transit support for the majority of the planet. It began its life as a transit-focused OpenTripPlanner frontend designed for regional deployments, but transit support took a back-seat as the need to scale became apparent. It turns out people like maps services more when those services work for getting around their own region, who knew?

At some point I became aware of the RAPTOR algorithm for transit routing, and in early 2024 I attempted to implement it to provide an infill service for the areas of the planet that maps.earth doesn’t host an OpenTripPlanner instance for. It was a bit of a false start. It’s a difficult thing to implement without errors. Imagine the a computer science student’s first time implementing quicksort and you’re on the right track. The code languished and was forgotten.

Now, in December 2024, I decided to plan a trip to California on a train. I did what any self-respecting transit nerd with a computer science degree would do—create her own transit routing software to plan her journey. I ended up hyper-focusing on the project so much that I missed my train and cancelled the trip, but that’s a story for another time. Starting from the husk of my old project and fueled by caffeine, I pretty quickly identified some of the major deficiencies and fixed them.

The result is hosted at https://farebox.airmail.rs/plan/<from>/<to>/ and accepts lat,lng pairs for each argument. It will also attempt to geocode addresses and POIs on a best-effort basis. Code for setting up your own is available on the GitHub repository. This instance is hosted in a tmux on my home server so don’t expect “miracles” or “uptime”. I sometimes even turn that server off if I have a telemedicine appointment or a big meeting.

Some sample queries

Between two parks in major US cities: https://farebox.airmail.rs/plan/Central%20Park,%20NYC/Millennium%20Park%20Chicago/

My favorite bakery to my favorite cheese shop: https://farebox.airmail.rs/plan/Lazy%20Cow%20Bakery%20Seattle/Cultured%20Kindness%20Portland/

Across the continental United States: https://farebox.airmail.rs/plan/Westlake%20Station%20Seattle/Central%20Park%20NYC/

Feel free to play around with it or set up your own. It’s pretty light on resources. My global instance took about 24 GiB of memory to build its timetable and consumes around 3 GiB to serve the data.

What else is out there

The notable alternatives to Farebox (working title, if you have ideas for better names let me know!) include OpenTripPlanner, MOTIS (see also: Transitous), Valhalla, and that’s about it to my knowledge. I’m omitting GraphHopper because last I checked it only works for a single GTFS feed. My “global” instance uses ~500, for comparison.

Of these, only MOTIS and Valhalla are capable of routing at this scale. I haven’t been able to extensively test either head-to-head, but from the spot checking I’ve done Farebox performs favorably against MOTIS, at least.

Where we go from here

There are still some issues preventing Farebox from correctly responding to some queries. For instance, it’s sometimes capable of serving routes from Barcelona to Berlin (in about a second, compare to MOTIS’s ~50s) but with the current timetable build those queries aren’t returning results.

The API also needs some work before it’s consumable by a downstream application. But that’s a project for another day. :)