OpenTripPlanner: A Self-Hosted Multi-Modal Trip Planner Built on GTFS and OpenStreetMap
An open source multi-modal trip planner
At a glance
- What is it?
- OpenTripPlanner is a Java server that turns GTFS feeds and OpenStreetMap data into a GraphQL trip planning API. It fits transit agencies and routing teams that need scheduled service, real-time updates and street-level modes in one graph.
- Who is it for?
- Adopt OpenTripPlanner if you control a GTFS feed and need scheduled transit combined with walking, cycling, bike share or ride hailing behind a GraphQL API you host yourself. Do not adopt it if you want a hosted journey planner with no data pipeline, or if you only need car routing over OpenStreetMap, where a lighter engine fits better.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 6 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 September 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What OpenTripPlanner Solves and Who It Is Built For
OpenTripPlanner (OTP) is an open source multi-modal trip planner. The README describes its focus as travel by scheduled public transportation combined with bicycling, walking, and mobility services including bike share and ride hailing. The people who need that combination are usually transit agencies, regional planning bodies, and engineering teams inside mobility companies. A single-mode router will answer a walking question or a driving question. OTP answers the question a rider actually asks: which bus, which walk to the stop, and which shared bike gets me the rest of the way, with disruptions taken into account.
The project has a long history. The README states it was launched by TriMet, Portland's transport agency, in July 2009, and that as of September 2025 it had been in development for over 16 years. The current branch is OpenTripPlanner 2, under development since 2018, which the README calls the dominant version and the only one being supported. That matters for anyone who finds older tutorials: OTP 1 material does not describe the system you would be running.
Two constraints shape who this is for. First, you supply the data. OTP builds its representation of the network from open data in open standard file formats, primarily GTFS and OpenStreetMap. Second, you run the server. The server component runs on any platform with a Java virtual machine, including Linux, Mac, and Windows. There is no hosted tier described in the README.
How the Graph, the Router and the GraphQL API Fit Together
The architecture visible in the repository splits into modules: `application/`, `core/`, `raptor/`, `street/`, `transit/`, `astar/`, `gtfs-realtime-protobuf/`, and `client/`. The names map to the work. Transit scheduling and street routing are separate concerns, and `raptor/` holds the range-based algorithm family that transit routing uses. The Maven build assembles everything into a single shaded JAR at `otp-shaded/target/otp-shaded-VERSION.jar` containing all necessary code and dependencies to run OpenTripPlanner. One file to deploy, which is a real operational simplification compared with a service that expects a cluster of sidecars.
Data flows in three stages. You give OTP a GTFS feed and an OpenStreetMap extract. OTP builds a graph from them. The server then exposes GraphQL APIs that can be accessed by various clients, including open source Javascript components and native mobile applications. Real-time updates and alerts are applied with immediate visibility to clients, so an itinerary can account for disruptions and service changes without a rebuild.
Two details in the README are worth reading carefully. The included Javascript client in `client/src/` is based on MapLibre and is described as now used for testing, with most major deployments building custom clients from reusable components. In other words, do not treat the bundled UI as the product. The API is the product. Second, the README points to a performance dashboard and a speed test included in the code that runs for every merged pull request. That is a statement about process, not a promise about your workload; the numbers depend on your feeds and your region.
Getting OpenTripPlanner Running and Planning a First Trip
The README does not print install commands. It points to the main documentation at docs.opentripplanner.org for a quick introduction, and the repository shows a Maven build producing `otp-shaded/target/otp-shaded-VERSION.jar`. A Docker image is published under the `opentripplanner/opentripplanner` name, which the README links through a Docker Pulls badge. Treat the documentation as the source of truth for flags and ports; the repository layout only tells you what gets built and where it lands.
There is no command to copy here, and inventing one would be worse than leaving it out. What the README gives is a destination: the basic tutorial in the main documentation, which walks through building a graph from your GTFS and OpenStreetMap files and then starting the server against that graph. The one artifact the repository does pin down is the output of the build, the unified file at `otp-shaded/target/otp-shaded-VERSION.jar` that the README says contains all necessary code and dependencies to run OpenTripPlanner. Expect the tutorial to hand you a build invocation and a serve invocation; expect the flags, the graph directory layout and the port to come from there, not from this article.
Once the server is up, queries go to the GraphQL endpoint. The README does not publish a query example or a port, so take both from the running server and the documentation rather than guessing field names. The intended consumers are the open source Javascript components and native mobile applications the README names. A Python caller is possible in principle because the transport is HTTP, which is why people search for opentripplanner python, but the README ships no Python client.
Where OpenTripPlanner Stops Being the Right Tool
The build step is the first real limitation. OTP does not query your GTFS feed live. It builds a graph, and that graph has to be rebuilt when the schedule changes. For a small agency with a stable timetable, a nightly rebuild is fine. For a feed that changes hourly, the rebuild cycle becomes the constraint you design around, and the README does not document an incremental rebuild path.
Real-time support is scoped to a format. The README ties live updates and alerts to GTFS-Realtime, and the repository carries a `gtfs-realtime-protobuf/` module. If your operator publishes delays through a proprietary API or a CSV drop, OTP has no documented path to ingest it. That is a hard boundary, not a configuration gap.
The bundled client is another place expectations run ahead of reality. The README says the MapLibre-based client in `client/src/` is now used for testing. Teams that pick OTP hoping to get a finished map interface will find themselves building one. The reusable components exist; the application does not.
Finally, memory. The graph for a large region is held in memory, and the README gives no sizing guidance. Capacity planning is something you do against your own region rather than something the project hands you.
OpenTripPlanner Versus GraphHopper and Other Routing Engines
The comparison people actually search for is opentripplanner vs graphhopper, and the difference is in what each engine treats as the primary problem. GraphHopper is built around routing over a street network, with OpenStreetMap as its input and a fast graph for car, bike and foot profiles. Transit is an add-on concern rather than the center of the model.
OTP inverts that. Its README describes the focus as scheduled public transportation in combination with other modes, and the repository gives transit its own module and its own algorithm family in `raptor/`. That means OTP is the better fit when the timetable is the thing that decides the answer, because a bus that leaves in four minutes changes the itinerary in a way no street-graph weight can express. GraphHopper is the better fit when you want a small, fast service for driving directions and transit is not on the table.
If you need isochrones, both projects can produce them, but the inputs differ in a way that changes the result. An isochrone from a street-only engine answers how far you can travel by road. An OTP isochrone can include scheduled service, which is what you want for accessibility analysis and what people search for as opentripplanner isochrone. The trade-off is that transit isochrones are only as good as the frequency data in the feed; a route that runs twice a day will produce a thin, irregular shape.
Maintenance, Licensing and the Cost of Staying Current
The repository is not archived, and the last push was on 2026-09-24. Releases are on a steady cadence: v2.10.0 in September 2026, v2.9.0 in March 2026, v2.8.1 in September 2025. That is roughly two releases a year, and the README states plainly that OTP 2 is the only version being supported. Running OTP 1 is not a maintenance strategy.
The upgrade cost is dominated by two things. Your GraphQL clients are tied to a schema that moves with releases, so a major version bump is a client-side migration as much as a server-side one. And your graph must be rebuilt against the new version, which is a data pipeline event, not a binary swap. The repository carries `ARCHITECTURE.md` and `DEVELOPMENT_DECISION_RECORDS.md`, which is where design changes get recorded; those files are the honest place to look before committing to a version.
On licensing, the repository root contains `LICENSE`, `lgpl-3.0.txt` and `publiccode.yml`, and the GitHub metadata reports the licence as NOASSERTION rather than a single SPDX identifier. That combination means the licence is not a one-line answer. Read `LICENSE` and `lgpl-3.0.txt` in the repository and get your own legal review before shipping OTP inside a product; the file layout suggests more than one licence is in play across the codebase, and I will not guess at the terms.
Editorial conclusion
Adopt OpenTripPlanner if you control a GTFS feed and need scheduled transit combined with walking, cycling, bike share or ride hailing behind a GraphQL API you host yourself. Do not adopt it if you want a hosted journey planner with no data pipeline, or if you only need car routing over OpenStreetMap, where a lighter engine fits better. Before committing, verify that your GTFS feed passes validation, that the region you need is covered by the OpenStreetMap extract you intend to load, and that your real-time feeds are in GTFS-Realtime format, because the README ties live updates and alerts to that standard.
Frequently asked questions
How do you use OpenTripPlanner?
You build a graph from a GTFS feed and an OpenStreetMap extract, then start the server against that graph and query its GraphQL API. The README points to the main documentation for a quick introduction covering the exact commands.
What is OpenTripPlanner?
It is an open source multi-modal trip planner focused on scheduled public transportation combined with bicycling, walking, bike share and ride hailing. Its server runs on any platform with a Java virtual machine and exposes GraphQL APIs.
How does OpenTripPlanner compare with GraphHopper?
OTP centers on scheduled transit, with a dedicated transit module and the RAPTOR algorithm family, and treats street modes as part of a multi-modal itinerary. GraphHopper is built around routing over a street network, so it fits better when transit is not part of the question.
What are the alternatives to OpenTripPlanner?
The README does not list alternatives. The main documented ecosystem pointer is the awesome-transit community list of transit APIs, apps, datasets, research and software, which is where related projects are collected.
Is there an open source journey planner available?
OpenTripPlanner is one: the README describes it as an open source multi-modal trip planner whose server runs on any Java virtual machine and whose code is developed by contributors worldwide. It builds its network representation from open data in open standard formats.
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/opentripplanner-opentripplanner)