GalwayBus: A Compose Multiplatform Transit App Fed by a Ktor GTFS Service
Galway Bus Kotlin Multiplatform project using Jetpack Compose and SwiftUI
At a glance
- What is it?
- GalwayBus is a Kotlin Multiplatform sample that renders one Compose UI on Android, iOS and Desktop (JVM) against a Ktor backend serving GTFS and GTFS-Realtime data. Its value is as a reference implementation of shared UI plus shared networking, not as a drop-in transit product.
- Who is it for?
- Adopt GalwayBus as a reading target if you want to see one Compose Multiplatform UI wired to Ktor, SQLDelight persistence and platform entry points, and use the jvmTest and iosSimulatorArm64Test tasks to check the shared module before trusting it. Do not adopt it as a transit product: the licence is not stated in the repository metadata, the bus data is Galway-specific, and there is no release artifact to pin.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Kotlin, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What GalwayBus Actually Solves, and for Whom
The README describes the product surface plainly: real-time departures for saved stops, stops near you, live on-map bus tracking with a journey timeline, and network-wide stop search. That is a consumer transit app for Galway city, and the data behind it is GTFS schedule plus GTFS-Realtime, served by a Ktor service the project also contains. The audience for the repository is narrower than the audience for the app. The README states that the project acted as an initial platform the author used when starting to explore Kotlin Multiplatform, and links to posts about SwiftUI with KMP, SQLDelight persistence, Google Maps in Compose, and scanning bus stop codes with ML Kit and Vision. So the primary reader is an engineer who wants to see a working KMP codebase with a shared UI rather than a shared-logic-only arrangement. If you are looking for a Galway bus app to install, the README points you at screenshots and run commands, not at a store listing.
One Compose UI, Three Targets, and the iosApp Entry Point
The architecture visible in the README is a shared module plus thin platform hosts. The /shared directory holds commonMain for code common to all targets, with iosMain and jvmMain for platform-specific Kotlin. The /iosApp directory is the iOS application, and the README is explicit about why it exists even when the UI is shared: you need that entry point for your iOS app, and it is where SwiftUI code belongs. That is the standard Compose Multiplatform split, and it is worth stating because it is the part people get wrong. Sharing the UI does not remove the need for a native host. The README also notes that the same Compose Multiplatform UI runs on Desktop (JVM), which is the target that makes the shared module testable without a device or simulator. Networking is Ktor, persistence is SQLDelight based on the linked post titles, and the dependency injection topic list names Koin. None of those wiring details appear in the README body itself, so treat the topic tags as hints rather than documentation.
Getting a Build Running on Each Target
The README gives concrete Gradle invocations. For Android: ./gradlew :androidApp:assembleDebug. For Desktop there are two modes, ./gradlew :desktopApp:hotRun --auto for hot reload and ./gradlew :desktopApp:run for a standard run. iOS is not a Gradle command at all: open the /iosApp directory in Xcode and run from there. Tests are split by target: ./gradlew :shared:testAndroidHostTest, ./gradlew :shared:jvmTest, and ./gradlew :shared:iosSimulatorArm64Test. The README also mentions run configurations in the IDE toolbar as an alternative. Note what is absent. There is no documented way to point the app at a different transit feed, no environment variable or config key for the Ktor service base URL, and no instructions for running the Ktor service locally. The README says the app is backed by a Ktor service that serves GTFS and GTFS-Realtime data, but it does not say where that service is deployed or how to start it. If you clone this repository expecting a self-contained stack, that gap is the first thing you will hit.
The Ktor Service Is the Part You Cannot Inspect from the README
Everything about the data path is asserted in one sentence and then left alone. The README states the app is backed by a Ktor service serving GTFS schedule and GTFS-Realtime data. It does not describe endpoints, response shapes, polling intervals, caching, or how the app handles a feed that goes stale. Those are the decisions that determine whether a transit client feels correct, and they are not documented here. The linked posts cover SQLDelight persistence and Google Maps usage, which suggests the on-device side is covered in prose elsewhere, but the service side is not. My judgement is that this is the weakest part of the repository as a reference. A reader can copy the Compose layout and the target split with confidence. A reader cannot copy the data layer without reading the source, and the README gives no pointer to where in the tree the Ktor routes live. Plan to spend your first hour in the repository reading code rather than documentation.
Where GalwayBus Is the Wrong Starting Point
Two constraints are worth naming before you commit. First, the data is Galway-specific. The README describes Galway city bus times and a network-wide stop search over that network; nothing suggests the app is feed-agnostic or configurable for another city. If your target is a different transit authority, you are looking at a UI and architecture reference, not a base to fork. Second, the repository metadata does not state a licence. The README carries no licence section and the supplied metadata lists the licence as unknown. That matters more here than in a typical sample, because the screenshots, the GTFS integration and the Ktor service are all things a commercial team might want to lift. Without a stated licence you have no grant to reuse anything, and I am not going to guess at terms. Treat the code as read-only until you confirm licensing with the author. A third, softer limitation: the README positions the project partly as a personal exploration vehicle. That framing is honest, but it means API stability across commits is not promised, and there are no releases to pin to.
How It Differs from a Shared-Logic KMP Setup
The obvious alternative is the common KMP arrangement where only business logic and networking live in the shared module and each platform keeps its own native UI, SwiftUI on iOS and Compose on Android. GalwayBus takes the other route: one Compose Multiplatform UI across Android, iOS and Desktop, with the iosApp directory reduced to an entry point and a place for SwiftUI where needed. The difference is not cosmetic. Sharing the UI means one rendering path to maintain and one set of layout bugs, and it means the Desktop target becomes a fast preview surface through ./gradlew :desktopApp:hotRun --auto. The cost is that anything Compose Multiplatform does not expose cleanly, such as a platform map SDK, has to be bridged, which is presumably why the README links posts about Google Maps in Compose and about ML Kit and Vision for scanning stop codes. If your app leans hard on native platform widgets, the shared-logic model will fight you less. If your screens are lists, maps and forms, the GalwayBus arrangement removes real duplication.
Maintenance Surface and What to Check Before Reusing Anything
The README badge pins Kotlin 2.4.0, so the Compose Multiplatform and Ktor versions are tied to that toolchain generation and will need to move together. There are no releases retrieved for this repository, which means no versioned artifact and no changelog to diff against; you track the main branch or you pin a commit yourself. The test tasks are the practical maintenance lever: ./gradlew :shared:jvmTest runs the shared module without a simulator, and ./gradlew :shared:iosSimulatorArm64Test covers the Apple target, so a Kotlin or Compose upgrade can be validated on the JVM first. On licensing, the honest position is that the repository metadata does not state one and the README does not either. Do not assume permissive terms, and do not treat the presence of a public repository as permission. The specific things to verify before adopting any of this: the SQLDelight schema if you intend to reuse persistence, the Ktor service contract if you intend to reuse the data layer, and the licence file if you intend to ship anything derived from it.
Editorial conclusion
Adopt GalwayBus as a reading target if you want to see one Compose Multiplatform UI wired to Ktor, SQLDelight persistence and platform entry points, and use the jvmTest and iosSimulatorArm64Test tasks to check the shared module before trusting it. Do not adopt it as a transit product: the licence is not stated in the repository metadata, the bus data is Galway-specific, and there is no release artifact to pin. Verify the SQLDelight schema and the Ktor service contract first, because those two files decide whether the shared module is reusable outside this app.
Community notes