Skip to content

Repository files navigation

node-GTFS

npm version monthly npm downloads build status MIT license

Import GTFS transit data into SQLite, PostgreSQL, or MySQL. Query, update with GTFS-Realtime, and export SQLite data from Node.js or the command line.

Choose what you want to do

Database support

Feature SQLite PostgreSQL MySQL
Import static GTFS Yes Yes, through Kysely Yes, through Kysely
Synchronous query helpers Yes No No
Import GTFS-Realtime Yes No No
Export GTFS files Yes No No
Manage GTFS tables and indexes Yes Optional Optional

PostgreSQL and MySQL imports use a caller-owned Kysely connection. See Database portability for storage details.

Note: PostgreSQL and MySQL support is new. The interface, configuration options, and functions related to it may change in a future release.

Requirements

Quick start

This example downloads BART's public GTFS feed and saves it as a persistent SQLite database.

1. Create a project

mkdir gtfs-demo
cd gtfs-demo
npm init -y
npm install gtfs

2. Import GTFS

npx gtfs-import \
  --gtfsUrl https://www.bart.gov/dev/schedules/google_transit.zip \
  --sqlitePath ./gtfs.sqlite

The import creates gtfs.sqlite in the current directory. If you don't specify a SQLite path when using the command line, it will default to an in-memory database which will be discarded when the command exits.

Warning: A static import drops and recreates the GTFS tables in its destination database. Use a new database or back up data you need to keep.

You can import your own ZIP file or directory instead:

npx gtfs-import --gtfsPath ./data/gtfs.zip --sqlitePath ./gtfs.sqlite

3. Query the database

Create a file named query.mjs:

import { closeDb, getAgencies, getRoutes, openDb } from 'gtfs';

const db = openDb({ sqlitePath: './gtfs.sqlite' });

try {
  const agencies = getAgencies({}, ['agency_id', 'agency_name']);
  const routes = getRoutes(
    {},
    ['route_id', 'route_short_name', 'route_long_name'],
    [['route_short_name', 'ASC']],
  );

  console.table(agencies);
  console.table(routes);
} finally {
  closeDb(db);
}

Run it:

node query.mjs

The .mjs extension lets Node.js run the example as an ES module without any additional project configuration.

Using JavaScript

Install node-GTFS in your application:

npm install gtfs

Import a feed and query it in the same process using an in-memory database:

import { closeDb, getStops, importGtfs, openDb } from 'gtfs';

const config = {
  agencies: [{ path: './data/gtfs.zip' }],
};

await importGtfs(config);
const db = openDb(config);

try {
  const stops = getStops(
    { stop_id: ['123', '234', '345'] },
    ['stop_id', 'stop_name'],
    [['stop_name', 'ASC']],
  );
  console.table(stops);
} finally {
  closeDb(db);
}

Methods that read SQLite data are synchronous. Import, export, and GTFS-Realtime updates are asynchronous.

Common tasks

Use a configuration file

A configuration file is useful for multiple feeds, custom HTTP headers, GTFS-Realtime endpoints, and other import options. Create config.json in the directory where you run the command:

{
  "agencies": [
    {
      "url": "https://www.bart.gov/dev/schedules/google_transit.zip"
    }
  ],
  "sqlitePath": "./gtfs.sqlite"
}

Then run:

npx gtfs-import

Use a configuration file in another location with --configPath:

npx gtfs-import --configPath ./config/production.json

See the configuration reference for every option and examples for multiple feeds, prefixes, exclusions, and custom logging. A comprehensive sample is also available.

Command-line tools

Installing gtfs provides three commands:

Command Purpose
gtfs-import Import static GTFS into SQLite
gtfsrealtime-update Refresh GTFS-Realtime data in SQLite
gtfs-export Export an SQLite database to GTFS files

Run any command with --help to see its options:

npx gtfs-import --help
npx gtfsrealtime-update --help
npx gtfs-export --help

You can install the commands globally with npm install --global gtfs, but a local installation with npx makes it easier to keep each project on a known version.

Query GTFS

Most getters have the same four optional arguments:

getRoutes(query, fields, orderBy, options);
  • query filters rows by field. An array means SQL IN; an empty array returns no rows.
  • fields selects returned columns. An empty array returns every column.
  • orderBy contains [field, 'ASC' | 'DESC'] pairs.
  • options can contain an explicit SQLite db connection.

For example, find trips for a route on a service date:

import { getTrips } from 'gtfs';

const trips = getTrips(
  { route_id: '12', date: 20260817 },
  ['trip_id', 'trip_headsign'],
  [['trip_headsign', 'ASC']],
  { db },
);

Specialized helpers support route, trip, service, time, geographic, and GeoJSON queries. See the query API guide.

Case-insensitive comparisons

Fields marked caseInsensitiveComparison in the schema use SQLite's COLLATE NOCASE. Equality, IN, and default ordering ignore ASCII letter case for those fields:

const agencies = getAgencies({ agency_name: 'metro transit' });

GTFS identifiers remain case-sensitive. SQLite NOCASE is not Unicode-aware. PostgreSQL and MySQL use the collation configured for their database or column.

GTFS-Realtime

Add one or more realtime endpoints to a feed in config.json:

{
  "agencies": [
    {
      "realtimeAlerts": {
        "url": "https://example.com/alerts.pb"
      },
      "realtimeTripUpdates": {
        "url": "https://example.com/trip-updates.pb"
      },
      "realtimeVehiclePositions": {
        "url": "https://example.com/vehicle-positions.pb"
      }
    }
  ],
  "sqlitePath": "./gtfs.sqlite"
}

Refresh the realtime tables:

npx gtfsrealtime-update

The command performs one update and exits. Use your operating system's task scheduler or a process manager to run it repeatedly. See the GTFS-Realtime guide for headers, retention, and JavaScript usage.

Export GTFS

Export an existing SQLite database:

npx gtfs-export --sqlitePath ./gtfs.sqlite

Or use JavaScript:

import { exportGtfs } from 'gtfs';

await exportGtfs({
  sqlitePath: './gtfs.sqlite',
  exportPath: './gtfs-export',
});

The export directory is replaced when an export runs. Make sure it does not contain files you need to keep.

PostgreSQL and MySQL

importGtfsToKysely() imports static GTFS using a caller-owned Kysely connection. Install the driver for your database in addition to gtfs.

Note: PostgreSQL and MySQL support is new. The interface, configuration options, and functions related to it may change in a future release.

PostgreSQL example:

npm install pg
import { importGtfsToKysely } from 'gtfs';
import { Kysely, PostgresDialect } from 'kysely';
import { Pool } from 'pg';

const db = new Kysely({
  dialect: new PostgresDialect({
    pool: new Pool({ connectionString: process.env.DATABASE_URL }),
  }),
});

try {
  await importGtfsToKysely(
    { agencies: [{ path: './data/gtfs.zip' }] },
    { db, dialect: 'postgres' },
  );
} finally {
  await db.destroy();
}

Warning: manageSchema defaults to true. The importer drops and recreates the GTFS tables it manages. Set manageSchema: false when your application owns the schema.

Use Kysely's MysqlDialect with mysql2 and dialect: 'mysql' for MySQL. Static Kysely imports do not store configured GTFS-Realtime feeds. See Database portability for schema requirements and generated columns.

TypeScript

TypeScript declarations are included. Configuration types include:

  • GtfsSqliteImportConfig for importGtfs()
  • GtfsImportConfig for importGtfsToKysely()
  • GtfsExportConfig for exportGtfs()
  • GtfsRealtimeConfig for updateGtfsRealtime()

Getter query fields, selected fields, and return values are inferred from the table schemas. Schema declarations and the GtfsDatabase Kysely type are exported from both gtfs and gtfs/schema. See the schema manifest.

Supported data

In addition to GTFS Schedule and GTFS-Realtime, node-GTFS includes schema and import support for:

The query API guide lists the public getters. Other imported tables can be read with SQL through the SQLite connection.

Troubleshooting

Start with the troubleshooting guide if a command is not found, the database is empty, the configuration cannot be parsed, or a native dependency does not install. Include the node-GTFS version, Node.js version, command, and complete error when opening an issue.

Example applications

Documentation

Contributing

Pull requests are welcome. Run the checks before submitting a change:

pnpm test
pnpm typecheck
pnpm lint
pnpm docs:check

node-GTFS is available under the MIT license.

About

Import GTFS transit data into SQLite and query routes, stops, times, fares and more.

Topics

Resources

Stars

503 stars

Watchers

21 watching

Forks

Releases

Packages

Used by

Contributors

Languages