Skip to content

Add NewRoutes to GTFS-RT to support dynamic service (#606) - #621

Open
cleveramarquet wants to merge 14 commits into
google:masterfrom
cleveramarquet:cleveramarquet-add-new-routes-proposal
Open

cleveramarquet wants to merge 14 commits into
google:masterfrom
cleveramarquet:cleveramarquet-add-new-routes-proposal

Conversation

@cleveramarquet

@cleveramarquet cleveramarquet commented Apr 9, 2026 •

Copy link
Copy Markdown

Description

This proposal introduces a NewRoutes message to the FeedEntity in GTFS Realtime. As discussed in Issue #606, the current specification lacks a standard way to define route metadata for services that do not exist in the static GTFS schedule.

The full technical specification and field definitions can be found in the GTFS-NewRoutes Google Doc.

By allowing a Route to be defined directly within the real-time feed, consumers can provide a complete and accurate experience for riders without requiring agencies to "reuse" unrelated static IDs.

Implementations

image

Proposal Update Tracker

Date Update Description
(2026-04-09) (Raised proposal)
(2026-10-19) (Discussion period started)
(2026-11-02) (Review period started)

Checklist

I have read and understood the GTFS Change process.
I have read and understood the GTFS Guiding Principles.
I understand the Role of Advocate and the Responsibilities attached to it.
I have signed the Contributor License Agreement (CLA).
I have ensured that this proposal is not covered by an existing Pull Request.

Add NewRoutes to proto
Comment thread gtfs-realtime/proto/gtfs-realtime.proto Outdated

// See definition of routes.route_type in (CSV) GTFS.
// Required
optional RouteType route_type = 6;

@leonardehrenfried leonardehrenfried Apr 9, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I did in the Google doc, I'm requesting this to be changed to an int so it can reflect the full range of extended route types. As a benefit this enum would then not have to be kept in sync with static GTFS.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @hbruch

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your point about the extended route types. However, I used an enum here to stay consistent with how the rest of the current GTFS-RT specification handles route types. Perhaps we could stick with the enum for this PR to keep the scope focused on NewRoutes, and then address a global move to int32 for route types across the entire spec in a separate proposal?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, since GTFS has ironclad backwards-compatibility guarantees, I don't think I will be able to convince the community that there are two ways to define the mode.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

100% agree with @leonardehrenfried.
We need extended route types support from the beginning so the feature can be useful.

(off topic: IMO the current GTFS route types should be deprecated and replaced with extended route types)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated route_type to int32 to support extended types as suggested. Thanks for the catch!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The move to int32 (should probably be uint32?) doesn't bother me, but it's really not obvious to me that extended route type is the way to go. There's been discussion in the past about this and it was contentious

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the status of the extended route types have been pretty frustrating for many years.

I'm aware that they are pretty unimportant in North America (correct?) but in Europe people very much like to separate their services into distinct types. From the perspective of a routing algorith, it may not matter much, but regular commuters care quite a lot about the difference between regional rail and suburban rail, for example.

I'm in favour of these distinctions, too, and would like to hear your opinions. If @gcamp, @felixguendling and I agree that it's worthwhile, we could try another attempt at standardising.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could try another attempt at standardising

I would support this as it's a very obvious shortcoming of GTFS compared to NeTEx and commercial proprietary data formats like HRDF, DIVA, ISA, etc. And it should be easy to fix because extended route types are used in practice in a lot of places already.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previous discussions:
issue#310, PR#279

We can continue route type discussion in #310

Change route_type to int32 to support extended route types per PR feedback
@gcamp

gcamp commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

@cleveramarquet You're missing the reference.md updates!

@leonardehrenfried

Copy link
Copy Markdown
Contributor

Thanks, @cleveramarquet, for yielding to my request.

@tzujenchanmbd

Copy link
Copy Markdown
Collaborator

Hi @cleveramarquet, Just a quick reminder based on CHANGES.md, a few conditions need to be met before initiating a vote:

The discussion lasts for as long as the advocate feels necessary, but must be at least 7 calendar days.

(Counted from when the PR is opened)

Before calling for a vote, at least one GTFS-realtime producer and one GTFS-realtime consumer should implement the proposed change. It is expected that the GTFS-realtime producer(s) include the change in a public-facing GTFS-realtime feed and provide a link to that data within the pull request comments, and that the GTFS-realtime consumer(s) provides a link in the pull request comments to an application that is utilizing the change in a non-trivial manner (i.e, it is supporting new or improved functionality).

("Development in progress" does not meet this requirement)

Given that these conditions are not currently met, we consider the current vote invalid. You may initiate another vote once all requirements are met.

Adding documentation for the Route message including route metadata, sort order, and activation dates to align with the NewRoutes proposal
Updated gtfs-realtime.proto to include:

route_sort_order (uint32) for display sequencing.

start_date and end_date (string) for route activation periods.
Added comments referencing the corresponding (CSV) GTFS definitions to maintain specification consistency.
@cleveramarquet

Copy link
Copy Markdown
Author

Thanks @leonardehrenfried and @felixguendling for the feedback. I have updated route_type to int32 in the .proto file and updated the documentation in reference.md to reflect this. This ensures we support the full range of extended route types from the start.

@gcamp I’ve just pushed an update that includes the reference.md changes. It now contains the full definitions for the Route message, including the route_sort_order, start_date, and end_date fields.

@tzujenchanmbd Thank you for the reminder on the CHANGES.md requirements. I’ve retracted the formal 'Call for Vote' for now.

I will leave the PR open for the required discussion period. In the meantime, I am working with the Transit App team to move their implementation from 'in-progress' to a state that meets the voting requirements. I'll provide the updated links once those are ready.

Regarding the route_type discussion, I’ve updated my PR to int32 to ensure NewRoutes is compatible with extended types immediately. However, to avoid overloading this proposal with a broader debate on global transit mode definitions, I suggest we move any further discussion on standardizing route_type across the rest of the spec to Issue #310 as suggested by @tzujenchanmbd.

@etienne0101 etienne0101 added GTFS Realtime Issues and Pull Requests that focus on GTFS Realtime labels Apr 27, 2026
Updated agency_id, route_short_name, and route_long_name to match the requirements in the GTFS-NewRoutes proposal document.
@felixguendling

Copy link
Copy Markdown

route_type should not stop us from making progress on this one, right?

The route_type field will stay, we can still standardize more values in a separate step together with GTFS-static route_type.

@cleveramarquet

Copy link
Copy Markdown
Author

route_type should not stop us from making progress on this one, right?

The route_type field will stay, we can still standardize more values in a separate step together with GTFS-static route_type.

That's correct @felixguendling, this should not stop us from making progress here. We can take care of standardizing more values for route_type in another pull request.

We are very close to having both public endpoints in between Hitachi (Clever Devices) and Transit running so we can officially put this pull request for a vote soon.

Peter-Ball added a commit to TransitApp/gtfs-realtime-bindings that referenced this pull request Aug 24, 2026
…#34)

Repoints the gtfs-spec submodule from the bare head of google/transit#621
to TransitApp/transit@vendored-with-proposals, which is upstream master
plus a merge commit per proposal we adopt early:

  #611  cyclist positions   VehiclePosition 12/13, CarriageDetails 6/7
  #621  NewRoutes           Route, FeedEntity.route, TripProperties.route_id

Previously the pin could only carry one in-flight proposal at a time,
since a submodule pin is a single commit and each PR head sits on its own
base. Pinning an integration branch lifts that limit and also recovers the
15 master commits both heads were missing (Alert.communication_period,
Alert.impact_period, Cause.SPECIAL_EVENT).

The pin stays fetchable through the existing .gitmodules URL: GitHub
serves any commit in a public fork network by SHA from the parent repo,
which is the same mechanism that made the previous pin work. No
.gitmodules change and no `git submodule sync` needed.

Node bindings regenerated (CJS + ESM + both .d.ts); version 1.11.0.
The diff against 1.10.0 is purely additive - no types removed.

Refreshing the branch: reset it to upstream master and re-merge each
still-open PR head. Never merge master into it - google/transit
squash-merges, so a landed PR arrives as a new commit that git will not
recognise as already applied.

Deleting it: once #611 and #621 have both landed upstream, repin gtfs-spec
to google/transit master and delete the branch.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@cleveramarquet

Copy link
Copy Markdown
Author

Hi @tzujenchanmbd /@gcamp, whenever you have a moment, could you please approve the pending workflow runs on this PR so the security scan can execute? Thank you!

@skalexch skalexch left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cleveramarquet I left one comment, route_id is missing from the table of TripProperties.

Also, there are mentions of route_id in reference.md. To me, it seems like all of these mentions are related to TripDescriptor and EntitySelector (e.g. lines 472 and 480), and the NewRoutes are only defined in TripProperties.

  1. Should we explicitly mention that all route_ids in TripDescriptor and EntitySelector should only reference static route_ids, and that dynamically created route_ids are only referenced via trip_properties?

    • I saw that the Google Doc of the proposal suggests referencing dynamically created routes in EntitySelector, but maybe that was removed from the scope of this proposal? I think if you're bringing it back, it opens a new conversation on whether it makes sense to link an alert to a route that isn't statically defined.
  2. Just a governance remark for future proposals, please make sure to include as much technical details as possible about the proposal in the body of the PR. Such as the details regarding inclusion in TripProperties, as well as one or two examples from the Google Doc. The doc should only be a complement to the information mentioned in the proposal.

  3. @tzujenchanmbd I think, at some point, we should elaborate on the definition of TripProperties in reference.md to make sure that the way it functions is clearer.

Comment thread gtfs-realtime/proto/gtfs-realtime.proto Resolved
@skalexch

Copy link
Copy Markdown
Collaborator

@cleveramarquet thanks for adding route_id in .proto and clarifying the scope of TripProperties.
One extra thing, you also need to add the description for route_id in the reference able for TripProperties here.

@cleveramarquet

cleveramarquet commented Oct 28, 2026 •

Copy link
Copy Markdown
Author

@skalexch thanks for adding route_id in .proto and clarifying the scope of TripProperties. One extra thing, you also need to add the description for route_id in the reference able for TripProperties here.

Done! Added the route_id description to the TripProperties table in reference.md. Thanks

Comment thread gtfs-realtime/spec/en/reference.md Resolved
Co-authored-by: Skander Chouchene <skander@mobilitydata.org>
@cleveramarquet

cleveramarquet commented Nov 2, 2026 •

Copy link
Copy Markdown
Author

Call for Vote
All required discussion time and implementation criteria have been met for this proposal.

Producer Implementation: Hitachi Test Feed

Consumer Implementation: Transit App

I am officially initiating a Call for Vote for the adoption of NewRoutes. Per the contribution guidelines, this voting window will remain open for at least 7 calendar days.

The voting period will span 1 week and will end on 2026-11-09 at 23:59:59 UTC.

@skalexch

skalexch commented Nov 2, 2026

Copy link
Copy Markdown
Collaborator

@cleveramarquet you need to put an exact end date and time to the vote to make sure we know which votes are valid. Here's an example.

@phil-swiftly

Copy link
Copy Markdown

Sorry for posting feedback comments during the voting period - if these are addressed Swiftly will vote +1.

@skalexch

skalexch commented Nov 5, 2026

Copy link
Copy Markdown
Collaborator

@phil-swiftly @cleveramarquet if the comments change the proposal substantially and are not just for the format, then the change cannot be made during the vote since it changes the scope of what's being voted on.

Also I cannot see the comments, did you submit the review?

@cleveramarquet

cleveramarquet commented Nov 10, 2026 •

Copy link
Copy Markdown
Author

Hi everyone,

Thank you again for all the progress and feedback on this proposal!

@phil-swiftly — Could you please share the specific points or comments you were referring to? I want to make sure everything is fully addressed.

Since we didn't quite reach the required quorum of supporting votes before the initial window closed, the vote is considered as failed. I am starting a new voting period to give everyone a bit more time to review and vote.

New Voting Window: Through 2026-11-17 at 23:59:59 UTC

@BethBeveridge, @felixguendling, and @leonardehrenfried — when you have a moment, would you mind taking a look and casting your votes? Thank you all so much for your help getting NewRoutes across the finish line!

@felixguendling

felixguendling commented Nov 10, 2026 •

Copy link
Copy Markdown

+1 MOTIS (consumer)

@skalexch

skalexch commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

@cleveramarquet could you please rebrand this as a new vote? It's fine for the time period, but once the first vote ended, it failed. You can just announce it as: "we closed the first vote on the 9th (failed) and opened a new vote that ends on the 17th)."

@cleveramarquet

Copy link
Copy Markdown
Author

you have a

@skalexch, yes of course. I updated the comment to reflect the new voting period. Thanks

@phil-swiftly phil-swiftly left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are the comments, sorry about the delay

Comment thread gtfs-realtime/spec/en/reference.md Resolved
| **trip_modifications** | [TripModifications](#message-tripmodifications) | Conditionally required | One | List of trips affected by a particular modifications, such as a detour. <br><br>**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. |

| **trip_modifications** | [TripModifications)(#message-tripmodifications) | Conditionally required | One | List of trips affected by a particular modifications, such as a detour. <br><br>**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. |
| **route** | [Route](#message-route) | Conditionally required | One | Data about a new route added to the feed dynamically, such as a bus bridge. <br><br>**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to clarify the Conditionally required status of this FeedEntity, I think route needs to be added to the list in the FeedEntity description of which at least one entity type must be entered. Link here

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phil-swiftly, thank you for the thorough review! I've added route to the FeedEntity conditionally required entity types list in the latest commits to reference.md. Let me know if this can be resolved.

Comment thread gtfs-realtime/spec/en/reference.md Outdated
| **shape_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the identifier of the shape of the vehicle travel path when the trip shape differs from the shape specified in (CSV) GTFS or to specify it in real-time when it's not provided by (CSV) GTFS, such as a vehicle that takes differing paths based on rider demand. See definition of `trips.shape_id` in (CSV) GTFS. <br>If a shape is neither defined in (CSV) GTFS nor in real-time, the shape is considered unknown. This field can refer to a shape defined in the (CSV) GTFS in shapes.txt or a `Shape` in the same (protobuf) real-time feed. The order of stops (stop sequences) for this trip must remain the same as (CSV) GTFS. If it refers to a `Shape` entity in the same real-time feed, the value of this field should be the one of the `shape_id` inside the entity, and _not_ the `id` of `FeedEntity`.<br>Stops that are a part of the original trip but will no longer be made, such as when a detour occurs, should be marked as schedule_relationship=SKIPPED or more details can be provided via a `TripModifications` message.<br><br>**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. |
| **trip_headsign** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the headsign for this trip when it differs from the original. <br><br>**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. |
| **trip_short_name** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the name for this trip when it differs from the original. <br><br>**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. |
| **route_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Optional | One | Specifies the route associated with the trip, if the route has been added dynamically. The associated `Route` message should be included in the same feed. <br><br>**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future.|

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should also note that this field is forbidden when schedule_relationship is not NEW. This is in the protobuf comments, but should also be included here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phil-swiftly, thank you for the thorough review! I've documented that route_id in TripProperties is optional when schedule_relationship is NEW and forbidden otherwise in the latest commits to reference.md. Let me know if this can be resolved.

Comment thread gtfs-realtime/spec/en/reference.md Outdated

| _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ |
| :--- | :--- | :--- | :--- | :--- |
| **route_id** | [string](https://protobuf.dev/programming-guides/proto2/#scalar) | Required | One | Identifier of the route. Must be different than any route_id defined in the static GTFS. |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we include the note from the Google Doc that route_id

Should not be reused for different disruptions or car pools on the same service day.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phil-swiftly, thank you for the thorough review! I've added the cautionary note regarding route_id reuse for different disruptions or car pools on the same service day. in the latest commits to reference.md. Let me know if this can be resolved.

cleveramarquet and others added 4 commits November 10, 2026 13:05
Co-authored-by: phil-swiftly <philip.cline@goswift.ly>
Clarified the shape entity to also document route as a choice
Addressed review feedback from @phil-swiftly:
- Included `route` in the `FeedEntity` description list of conditionally required entity types.
- Noted that `route_id` in `TripProperties` is forbidden when `schedule_relationship` is not `NEW`.
- Added a cautionary note that `route_id` should not be reused for different disruptions or car pools on the same service day.
Added a cautionary note that `route_id` should not be reused for different disruptions or car pools on the same service day.

@cleveramarquet cleveramarquet left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed review feedback from @phil-swiftly on PR #621:

  • Included route in the FeedEntity description list of conditionally required entity types.
  • Noted that route_id in TripProperties is optional if schedule_relationship is NEW, and forbidden otherwise.
  • Added a cautionary note that route_id should not be reused for different disruptions or car pools on the same service day.

@skalexch

skalexch commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator

@cleveramarquet according to the RT governance, "During voting period only editorial changes to the proposal are allowed (typos, wording may change as long as it does not change the meaning)."

The changes that were made during the vote constitute more than that. Unfortunately, that means the current vote is not valid. Therefore, it is better to stop it.

We recommend keeping the proposal open for a week just to make sure the changes you made are visible to community members, then you can start the vote to adopt NewRoutes.

Tagging @phil-swiftly (for having requested the changes) and @felixguendling (for having voted).

@cleveramarquet

Copy link
Copy Markdown
Author

Based on the governance feedback from @skalexch regarding the substantive updates made during the active voting window, we are officially canceling the current vote.

Per the GTFS contribution guidelines, I am placing the PR back into a 1-week review mode effective today so that community members can review the latest changes to reference.md. Once this review period concludes, we will initiate a fresh Call for Vote.

Thank you everyone for your patience and feedback!

@felixguendling

Copy link
Copy Markdown

If we're back to review mode anyhow: when processing the Protobuf file, it's most efficient to go through it linearly from begin to end in a single pass. If trip updates use the new route, it would help for consumers if the route has already been parsed when it's referenced. So I would propose to add a rule that requires that all entities that are referenced to be earlier in the list than the first entity that references it. This would also be nice to have for Stop entities (new stops), shapes, etc. If everything comes in the right order, that would allow consumers to read the feed update in a single pass instead of multiple passes (one to create entities and the second to apply the actual updates).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

GTFS Realtime Issues and Pull Requests that focus on GTFS Realtime

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants