We provide a Java library for reading and writing GTFS feeds, including database support.

Current Version: 1.3.94-SNAPSHOT

Details on all releases can be found in the Release Notes.

The library is broken up into a few key modules:

  • onebusaway-gtfs - The core library for reading and writing GTFS
  • onebusaway-gtfs-hibernate - Support for Hibernate database persistence of GTFS data
  • onebusaway-gtfs-hibernate-cli - Command-line utilty for loading GTFS feeds into a database - see the full documentation.
  • onebusaway-gtfs-transformer - Tools for transforming GTFS data
  • onebusaway-gtfs-transformer-cli - Command-line utility for transforming GTFS - see the full documentation.
  • onebusaway-gtfs-merge - Tools for merging GTFS data
  • onebusaway-gtfs-merge-cli - Command-line utility for merging GTFS feeds - see the full documentation.


You can access the latest Javadoc for the library. Also, see example source code below.

Using in Maven

The library is available as a Maven module. Simply add the following dependencies:

    <!-- Core GTFS Library -->
    <!-- Optional Hibernate GTFS Database Persistence -->
    <!-- Optional GTFS Transformation Library -->

To use a SNAPSHOT version of the library, you'll need to add a reference to the OneBusAway Maven repository.

Example Code

Basic Reading

Let's introduce basic code for reading a GTFS feed and handling the resulting entities:

public class GtfsReaderExampleMain {

  public static void main(String[] args) throws IOException {

    if (args.length != 1) {
      System.err.println("usage: gtfs_feed_path");

    GtfsReader reader = new GtfsReader();
    reader.setInputLocation(new File(args[0]));

     * You can register an entity handler that listens for new objects as they
     * are read
    reader.addEntityHandler(new GtfsEntityHandler());

     * Or you can use the internal entity store, which has references to all the
     * loaded entities
    GtfsDaoImpl store = new GtfsDaoImpl();

    // Access entities through the store
    for (Route route : store.getAllRoutes()) {
      System.out.println("route: " + route.getShortName());

  private static class GtfsEntityHandler implements EntityHandler {

    public void handleEntity(Object bean) {
      if (bean instanceof Stop) {
        Stop stop = (Stop) bean;
        System.out.println("stop: " + stop.getName());

Notice that the GtfsReader does the bulk of the work of reading the GTFS feed. The general pattern is to create the reader, set the input file, and call `run()` to start the reading process. You can manage the resulting GTFS entities in a couple of ways:

  • Register an EntityHandler to handle entities as they are read
  • Use an instance of GenericMutableDao to examine the loaded entities after reading is complete

Basic Writing

public class GtfsWriterExampleMain {

  public static void main(String[] args) throws IOException {

    if (args.length != 1) {
      System.err.println("usage: gtfs_feed_path");

    GtfsWriter writer = new GtfsWriter();
    writer.setOutputLocation(new File(args[0]));

    Agency agency = new Agency();
    agency.setName("My agency!");

    Route route = new Route();



Basic Database Reading

The class org.onebusaway.gtfs.examples.GtfsHibernateReaderExampleMain in the onebusaway-gtfs-hibernate/src/test/java directory includes basic code for reading a GTFS feed into a database and querying the resulting entities.

The sample code has been summarized for length and clarity:

public class GtfsHibernateReaderExampleMain {

  public static void main(String[] args) throws IOException {

    // Check args and construct application resource paths

    HibernateGtfsFactory factory = createHibernateGtfsFactory(resource);

    GtfsReader reader = new GtfsReader();
    reader.setInputLocation(new File(args[0]));

    GtfsMutableRelationalDao dao = factory.getDao();

    Collection<Stop> stops = dao.getAllStops();

    for (Stop stop : stops)


  // Other methods
  private static HibernateGtfsFactory createHibernateGtfsFactory(String resource) {

    Configuration config = new Configuration();

    if (resource.startsWith(KEY_CLASSPATH)) {
      resource = resource.substring(KEY_CLASSPATH.length());
      config = config.configure(resource);
    } else if (resource.startsWith(KEY_FILE)) {
      resource = resource.substring(KEY_FILE.length());
      config = config.configure(new File(resource));
    } else {
      config = config.configure(new File(resource));

    SessionFactory sessionFactory = config.buildSessionFactory();
    return new HibernateGtfsFactory(sessionFactory);

This code is roughly similar to the example reader code for onebusaway-gtfs, with the main difference being the use of HibernateGtfsFactory, which is a convenience factory for creating database-aware DAOs.

Configuring Your Database

By default, the example above is setup to run with an in-memory HSQLDB database. Obviously, it'd be great to configure it to use a different database and you totally can. See for more documentation on configuring Hibernate, but also check out the default hibernate config file used in the example above. It's located in the following directory:


The contents look like:

<?xml version='1.0' encoding='utf-8'?>
        <!-- Database connection settings -->
        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
        <property name="connection.url">jdbc:hsqldb:mem:org_onebusaway_temporary</property>
        <property name="connection.username">sa</property>
        <property name="connection.password"></property>

        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.HSQLDialect</property>

        <!-- More config options removed for brevity -->

Here you can configure the data source used for the database connection along with the Hibernate dialect.

Reading Custom Fields

Does your GTFS feed have custom fields not defined by the core onebusaway-gtfs library? It's possible to read and write this data without modify OBA source code using the "extensions" mechanism. Consider a stops.txt file with a custom extra_stop_info field:

123,Some Station,47.0,-122.0,This is a cool transit station

The extra_stop_info field isn't included in the the Stop data model by default. So instead, we define a special StopExtension Java bean type with the new field:

public static class StopExtension {
  @CsvField(optional = true)
  private String extraStopInfo;

  public String getExtraStopInfo() { ... }
  public void setExtraStopInfo(String info) { ... }

We can now register our class as an extension of the default stop data model:

DefaultEntitySchemaFactory factory = GtfsEntitySchemaFactory.createEntitySchemaFactory();
factory.addExtension(Stop.class, StopExtension.class);
GtfsReader reader = new GtfsReader();

Now when you read your GTFS feed with the GtfsReader instance, StopExtension objects will automatically be created, populated, and attached to stops as they are read:

Stop stop = dao.getStopForId(...);
StopExtension extension = stop.getExtension(StopExtension.class);

For more information on defining the mapping from GTFS fields to Java beans, see documentation for the onebusaway-csv-entities project, including the @CsvField annotation documentation.