Configuration reference

August 23, 2026 ยท View on GitHub

node-GTFS accepts configuration objects in JavaScript and JSON configuration files on the command line. Relative paths are resolved from the directory where the process is started.

The repository includes three starting points:

Replace the example URLs, credentials, and paths before using the full samples. The db and logFunction options are JavaScript values and cannot be stored in JSON. The deprecated verbose option is omitted; use logLevel instead.

Below is a minimal configuration:

{
  "agencies": [
    {
      "path": "./data/gtfs.zip"
    }
  ],
  "sqlitePath": "./data/gtfs.sqlite"
}

agencies is required for static imports. sqlitePath is strongly recommended for command-line use because the default is an in-memory database.

Warning: A static import drops and recreates the GTFS tables in its destination database. It does not preserve changes made directly to those tables. Use a new database or create a backup before importing.

Top-level options

OptionTypeDefaultUsed byDescription
agenciesarrayrequiredimport, realtimeGTFS feeds to process
sqlitePathstring:memory:SQLite operationsSQLite database path
dbbetter-sqlite3 databasenoneJavaScript SQLite operationsExisting connection to use
csvOptionsobject{}static importOptions passed to csv-parse
downloadTimeoutnumber30000import, realtimeDownload timeout in milliseconds
exportPathstringgeneratedexportDirectory for exported files
gtfsRealtimeExpirationSecondsnumber0realtimeAge at which old realtime rows may be deleted
ignoreDuplicatesbooleanfalsestatic importSkip rows that violate a unique key
ignoreErrorsbooleanfalseimport, realtimeLog an error and continue where supported
includeImportReportbooleanfalsestatic importReturn an ImportReport from JavaScript
logLevelstringinfoall operationssilent, error, warning, or info
logFunctionfunctionconsoleJavaScript operationsReceive non-progress log messages
verbosebooleannoneall operationsDeprecated; use logLevel

You can add your own unrelated config options - unknown keys are ignored, although likely misspellings of known options produce a warning.

Feed options

Each static feed must have exactly one url or path.

OptionTypeDescription
urlstringURL of a GTFS ZIP file
pathstringLocal ZIP file or directory containing GTFS files
headersobjectHTTP request headers for the static feed
prefixstringPrefix applied to identifiers when feeds are merged
excludestring arrayDatabase table names to skip, without .txt
fillEmptyAgencyIdbooleanFill missing agency_id values in a single-agency feed
agencyIdstringFallback ID used with fillEmptyAgencyId
realtimeAlertsobjectAlert endpoint and optional headers
realtimeTripUpdatesobjectTrip update endpoint and optional headers
realtimeVehiclePositionsobjectVehicle position endpoint and optional headers

Import from a URL

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

Import from a ZIP file or directory

{
  "agencies": [
    {
      "path": "./data/gtfs.zip"
    }
  ],
  "sqlitePath": "./data/gtfs.sqlite"
}

Change path to a directory such as ./data/unzipped-gtfs when the feed has already been extracted.

Send HTTP headers

{
  "agencies": [
    {
      "url": "https://example.com/gtfs.zip",
      "headers": {
        "Authorization": "Bearer replace-with-your-token"
      }
    }
  ],
  "sqlitePath": "./gtfs.sqlite"
}

Do not commit credentials to source control. Load configuration from a secure location in production.

Merge multiple feeds

Use a different prefix for each feed when their identifiers may overlap:

{
  "agencies": [
    {
      "path": "./data/north.zip",
      "prefix": "north"
    },
    {
      "path": "./data/south.zip",
      "prefix": "south"
    }
  ],
  "sqlitePath": "./regional.sqlite"
}

Only schema fields marked applyFeedPrefix are changed. The prefix is also applied to corresponding references.

Exclude large or unused tables

exclude uses database table names, not filenames:

{
  "agencies": [
    {
      "path": "./data/gtfs.zip",
      "exclude": ["shapes", "fare_attributes"]
    }
  ],
  "sqlitePath": "./gtfs.sqlite"
}

Fill empty agency IDs

Some valid single-agency feeds leave agency_id blank throughout the GTFS. Set fillEmptyAgencyId to fill those values:

{
  "agencies": [
    {
      "path": "./data/gtfs.zip",
      "fillEmptyAgencyId": true,
      "agencyId": "metro-transit"
    }
  ],
  "sqlitePath": "./gtfs.sqlite"
}

An ID found in agency.txt takes precedence over agencyId.

Import GTFS-realtime data too

{
  "agencies": [
    {
      "url": "https://svc.metrotransit.org/mtgtfs/gtfs.zip",
      "realtimeAlerts": {
        "url": "https://svc.metrotransit.org/mtgtfs/alerts.pb"
      },
      "realtimeTripUpdates": {
        "url": "https://svc.metrotransit.org/mtgtfs/tripupdates.pb"
      },
      "realtimeVehiclePositions": {
        "url": "https://svc.metrotransit.org/mtgtfs/vehiclepositions.pb"
      }
    }
  ],
  "sqlitePath": "./gtfs.sqlite"
}

See the GTFS-Realtime guide for more details.

Existing SQLite connection

Pass a caller-owned better-sqlite3 connection with db. This is available only from JavaScript, not JSON:

import Database from 'better-sqlite3';
import { importGtfs } from 'gtfs';

const db = new Database('./data/gtfs.sqlite');

try {
  await importGtfs({
    agencies: [{ path: './data/gtfs.zip' }],
    db,
  });
} finally {
  db.close();
}

The caller remains responsible for the connection lifecycle.

CSV parser options

csvOptions is passed to csv-parse. For example:

{
  "agencies": [{ "path": "./data/gtfs.zip" }],
  "sqlitePath": "./gtfs.sqlite",
  "csvOptions": {
    "skip_empty_lines": true
  }
}

Parser options can change which data is accepted. Validate the resulting record counts when relaxing parsing behavior.

Error handling

With ignoreErrors: false, an import stops at the first error. With ignoreErrors: true, node-GTFS logs errors and continues with later work where possible. A parser or database error can cause the rest of the current file or batch to be skipped, and previously committed batches remain in the database. The result may therefore be partial.

Use includeImportReport in JavaScript to inspect the result:

import { importGtfs } from 'gtfs';

const report = await importGtfs({
  agencies: [{ path: './data/gtfs.zip' }],
  sqlitePath: './gtfs.sqlite',
  ignoreErrors: true,
  includeImportReport: true,
});

console.log(report.errors);

In TypeScript, the literal includeImportReport: true changes the return type to Promise<ImportReport>.

ignoreDuplicates skips records that violate a declared unique key. It does not make other parse or database errors non-fatal.

Logging

logLevel accepts silent, error, warning, or info. Errors and warnings use stderr; normal status output uses stdout.

JavaScript applications can redirect non-progress messages:

import { importGtfs } from 'gtfs';

await importGtfs({
  agencies: [{ path: './data/gtfs.zip' }],
  sqlitePath: './gtfs.sqlite',
  logLevel: 'warning',
  logFunction(message, level) {
    console.log(`[${level}] ${message}`);
  },
});

The level argument is optional, so existing logFunction(message) callbacks continue to work.

verbose remains available for compatibility. Use logLevel in new code.

Export path

If exportPath is omitted, exports go to gtfs-export/<first-agency-name> under the current directory. The export directory is cleared before files are written.

{
  "sqlitePath": "./gtfs.sqlite",
  "exportPath": "./output/gtfs"
}

Command-line precedence

The commands look for ./config.json in the current working directory unless --configPath is supplied. Direct command-line options override values with the same name in the selected configuration file.

npx gtfs-import \
  --configPath ./config.json \
  --sqlitePath ./temporary.sqlite \
  --logLevel warning

Run a command with --help for its current options.