Singapore Buses v2026
A look at some of the technical changes made to Singapore Buses.

Singapore Buses v2026 is out now. It's been a challenging development cycle, to say the least, and I'm glad it's over. The Design Diaries series covers the major Liquid Glass updates. This post looks at some of the other technical changes that have been made in the v2026 update.
GRDB
Singapore Buses, has always, always, always—way back to 2018 when it was SG Transit—used Core Data. Even when SwiftUI came along, followed by SwiftData, it stuck with Core Data. Not any more. It's now using GRDB.
Each app version is seeded with an updated SQLite
database containing the latest bus stops, routes, and services. This database is created using a separate app on the Mac. Long-term, the aim is to move away from having to release new app versions with an up-to-date database and instead move to an over-the-air model that refreshes the database in the background. The move to GRDB should smooth the path.
Map Performance
The database is now loaded into memory instead of being read from disk. As a result, panning the map and determining what bus stops to show (or hide) is now instantaneous instead of requiring a small pause and the end of the pan gesture. It's a simple call site:
.onMapCameraChange(frequency: .continuous) { context in
model.showStops = context.camera.distance < 9500 // hide stops when above 9,500m
Task {
await model.updateVisibleBusStops(context.rect)
}
}
App Clip
Singapore Buses now contains an App Clip with arrival estimate UI.
When users share estimated arrival times from the main app, text is generated with the current arrival times along with a URL: https://clips.singaporebuses.app?...
That URL has the following query parameters:
Parameter | Usage | Example |
---|---|---|
c | Bus Stop Code | 08138 |
n | Bus Stop Name | Concorde Hotel S'pore |
r | Road Name | Orchard Rd |
s | Service No | 174 |
lat | Latitude | 1.3004785730821 |
lon | Longitude | 103.841847006076 |
e | Expiry | 1757767987 |
v | HMAC Validation | signature |
The parameters c
, n
, and r
are used to populate the UI in the App Clip, while lat
and lon
are used to determine if a Look Around view can be displayed. s
in conjunction with c
are used to query the LTA API for the latest estimates. e
is the time the App Clip expires, and v
is a signature that is validated to make sure the URL is genuine.
If the recipient has Singapore Buses installed, tapping the link opens the app and presents arrivals for that bus stop. Otherwise, an App Clip launches with the same bus arrival UI as the main app and updates arrival estimates every 15 seconds for 10 minutes...then invites the user to download the app from the App Store.
The clips.singaporebuses.app
subdomain is powered by Cloudflare Workers. It serves an AASA, some basic content, and a favicon, but is otherwise is there to enable redirects to the app or the App Clip.
This is the first time I've implemented an App Clip. I'm interested to see how (or if) it affects download statistics.
iPad Support
Given that iPadOS is, in my opinion, the star of the 26 series of OS updates, it only made sense to extend Singapore Buses to the iPad. It now has a native layout with some iPad specific niceties, like keyboard shortcuts and a full-screen route views.
(I've never seen anyone actually use an iPad at a bus stop in Singapore. With that in mind, Singapore Buses will be on Apple Watch in the future.)
LandTransportKit
Lastly, all interaction with the Land Transport API is now handled with LandTransportKit.
I've open sourced this package—it's free for anyone to use!
Discussion