Bus Times: Dublin & Ireland
Live public transport departures for Ireland
An unofficial companion for Irish bus, tram and rail. It answers one question — do I run or do I have time? — and it has to be right, so it distinguishes clearly between real-time and scheduled departures.
- Expo
- React Native
- TypeScript
- Cloudflare Workers
- R2
- SwiftUI
- WidgetKit
- GitHub Actions
The whole stack, not just the app
A Node pipeline turns the 250 MB national GTFS feed into roughly 10,200 per-stop JSON files in Cloudflare R2. A Worker serves them, polls the GTFS-Realtime feed on a cron, and holds LRU caches, kill switches and a per-IP rate limit.
A 503 rate of 26–33%, measured and fixed
Batch requests for ~20 Cork stops blew the Worker's 10 ms CPU budget on a cold isolate. Splitting into chunks of eight gave each its own budget, and Promise.allSettled meant one bad chunk cost eight stops instead of the whole list. Failure rate went to zero.
A widget that updates itself while the app is closed
Scheduled departure times are deterministic — only the live delay drifts. So instead of trying to wake the widget, it pushes a 12-entry timeline covering an hour and lets iOS walk it, each entry recomputing from the absolute due time.
Native Apple Watch app in SwiftUI
The watch mirrors data the phone already fetched over WatchConnectivity, so it costs nothing extra on the backend. Payloads are deduplicated before transfer because the complication quota is about fifty pushes a day.
CI that repairs itself
The national feed rotates trip IDs periodically, which silently broke real-time matching. A scheduled workflow fingerprints trips.txt and rebuilds only when it actually changes.








