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.
- Import and explore a feed locally: follow the SQLite quick start.
- Use node-GTFS in an application: see Using JavaScript.
- Load an existing PostgreSQL or MySQL database: see PostgreSQL and MySQL.
- Refresh GTFS-Realtime data: see GTFS-Realtime.
- Export a database back to GTFS files: see Export GTFS.
| 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.
- Node.js 22 or newer
This example downloads BART's public GTFS feed and saves it as a persistent SQLite database.
mkdir gtfs-demo
cd gtfs-demo
npm init -y
npm install gtfsnpx gtfs-import \
--gtfsUrl https://www.bart.gov/dev/schedules/google_transit.zip \
--sqlitePath ./gtfs.sqliteThe 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.sqliteCreate 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.mjsThe .mjs extension lets Node.js run the example as an ES module without any
additional project configuration.
Install node-GTFS in your application:
npm install gtfsImport 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.
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-importUse a configuration file in another location with --configPath:
npx gtfs-import --configPath ./config/production.jsonSee the configuration reference for every option and examples for multiple feeds, prefixes, exclusions, and custom logging. A comprehensive sample is also available.
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 --helpYou 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.
Most getters have the same four optional arguments:
getRoutes(query, fields, orderBy, options);queryfilters rows by field. An array means SQLIN; an empty array returns no rows.fieldsselects returned columns. An empty array returns every column.orderBycontains[field, 'ASC' | 'DESC']pairs.optionscan contain an explicit SQLitedbconnection.
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.
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.
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-updateThe 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 an existing SQLite database:
npx gtfs-export --sqlitePath ./gtfs.sqliteOr 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.
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 pgimport { 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:
manageSchemadefaults totrue. The importer drops and recreates the GTFS tables it manages. SetmanageSchema: falsewhen 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 declarations are included. Configuration types include:
GtfsSqliteImportConfigforimportGtfs()GtfsImportConfigforimportGtfsToKysely()GtfsExportConfigforexportGtfs()GtfsRealtimeConfigforupdateGtfsRealtime()
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.
In addition to GTFS Schedule and GTFS-Realtime, node-GTFS includes schema and import support for:
- GTFS-Plus
- GTFS-Ride
- GTFS-to-HTML timetable files
- Transit Operational Data Standard (TODS)
- TIDES
- NOPTIS
The query API guide lists the public getters. Other imported tables can be read with SQL through the SQLite connection.
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.
- GTFS-to-HTML generates transit timetables.
- GTFS-to-GeoJSON creates GeoJSON for transit routes.
- GTFS-to-Chart generates stringline charts.
- GTFS Accessibility Validator checks accessibility-related GTFS fields.
- GTFS Text-to-Speech tests stop name pronunciation.
- Transit Departures Widget displays realtime departures.
- GTFS-to-Blocks exports trip segments grouped by block.
- Configuration reference
- Query API guide
- GTFS-Realtime guide
- Troubleshooting
- Database portability
- Schema manifest
Pull requests are welcome. Run the checks before submitting a change:
pnpm test
pnpm typecheck
pnpm lint
pnpm docs:checknode-GTFS is available under the MIT license.