README.md
August 18, 2026 ยท View on GitHub
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
- 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.
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
- Node.js 22 or newer
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);
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.
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:
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
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.
Supported data
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.
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
- 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.
Documentation
- Configuration reference
- Query API guide
- GTFS-Realtime guide
- Troubleshooting
- Database portability
- Schema manifest
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.