Skip to main content
The fastest way to use mta-js is the hosted API at mtaapi.dev. Pass apiKey and you’re done — no BusTime key, no GTFS imports, no stop search setup.Self-host only when you need full control over the data path, want to deploy in an air-gapped environment, or have already invested in MTA developer credentials. Everything below is for that case.
In direct-feed mode, mta-js talks straight to MTA’s realtime GTFS-RT and BusTime APIs. The public method names (mta.subway.arrivals, mta.bus.arrivals, mta.bus.vehicles, mta.alerts.current, mta.stops.near) stay the same — only the constructor changes.
Direct-feed mode has no bundled database in mta-js 2.0. There’s no SQLite, no Turso, and no persistent GTFS storage. Stop lookups rely on the optional in-memory staticData seed described below. For production stop search, prefer the hosted API — it serves a compact Blob-backed snapshot so SDK consumers don’t have to manage GTFS imports.

Direct-feed client

Pass a busTimeKey instead of an apiKey:
Subway feeds and service alerts work without any key. busTimeKey is only required for bus realtime endpoints (mta.bus.arrivals, mta.bus.vehicles) — request one from the MTA BusTime developer portal.

Adding stop and route metadata

Without the hosted API, mta-js has no built-in GTFS database, so stop and route names won’t resolve automatically. Pass a small in-memory staticData seed to get richer local metadata for the stops you care about:
This is intended for a handful of well-known stops, internal tooling, or tests. It is not a replacement for full GTFS static data. If you need comprehensive stop search across the system, use the hosted API.

Constructor options

Framework integration

Still deciding? Start with mtaapi.dev. You can switch to direct-feed mode later without changing your application code — only the constructor options change.