This release adds two new artifacts that contain Jetpack compose extensions amongst other fixes.
Many thanks to @slinstacart and @hbmartin for their contributions to this release!
You can now use the apollo-compose-support artifact:
// build.gradle.kts
dependencies {
implementation("com.apollographql.apollo3:apollo-compose-support")
}
This artifact contains the toState() and watchAsState() extensions:
/**
* A stateful composable that retrieves your data
*/
@OptIn(ApolloExperimental::class)
@Composable
fun LaunchDetails(launchId: String) {
val response by apolloClient.query(LaunchDetailsQuery(launchId)).toState()
val r = response
when {
r == null -> Loading() // no response yet
r.exception != null -> ErrorMessage("Oh no... A network error happened: ${r.exception!!.message}")
r.hasErrors() -> ErrorMessage("Oh no... A GraphQL error happened ${r.errors[0].message}.")
else -> LaunchDetails(r.data!!, navigateToLogin)
}
}
/**
* A stateless composable that displays your data
*/
@Composable
private fun LaunchDetails(
data: LaunchDetailsQuery.Data,
) {
// Your UI code goes here
}
If you are working with paginated data, you can also add apollo-compose-paging-support to your dependencies:
// build.gradle.kts
dependencies {
implementation("com.apollographql.apollo3:apollo-compose-paging-support")
}
This artifact contains a helper function to create androidx.pagin.Pager instances (androix documentation):
@OptIn(ApolloExperimental::class)
@Composable
fun LaunchList(onLaunchClick: (launchId: String) -> Unit) {
val lazyPagingItems = rememberAndCollectPager<LaunchListQuery.Data, LaunchListQuery.Launch>(
config = PagingConfig(pageSize = 10),
appendCall = { response, loadSize ->
if (response?.data?.launches?.hasMore == false) {
// No more pages
null
} else {
// Compute the next call from the current response
apolloClient.query(
LaunchListQuery(
cursor = Optional.present(response?.data?.launches?.cursor),
pageSize = Optional.present(loadSize)
)
)
}
},
getItems = { response ->
// Compute the items to be added to the page from the current response
if (response.hasErrors()) {
Result.failure(ApolloException(response.errors!![0].message))
} else {
Result.success(response.data!!.launches.launches.filterNotNull())
}
},
)
// Use your paging items:
if (lazyPagingItems.loadState.refresh is LoadState.Loading) {
Loading()
} else {
LazyColumn {
items(lazyPagingItems) { launch ->
// Your UI code goes here
}
item {
when (val append = lazyPagingItems.loadState.append) {
is LoadState.Error -> // Add error indicator here
LoadState.Loading -> // Add loading indicator here
}
}
}
}
}
As always, feedback is very welcome. Let us know what you think of the feature by either opening an issue on our GitHub repo , joining the community or stopping by our channel in the KotlinLang Slack(get your invite here).
If you import a new project or run a Gradle sync, your GraphQL models are now automatically generated so that the IDE can find the symbols and your files do not show red underlines. This takes into account Gradle up-to-date checks and it should be pretty fast. If you want to opt-out, you can do so with generateSourcesDuringGradleSync.set(false):
apollo {
// Enable automatic generation of models during Gradle sync (default)
generateSourcesDuringGradleSync.set(true)
// Or disable automatic generation of models to save on your Gradle sync times
generateSourcesDuringGradleSync.set(false)
service("api") {
// Your GraphQL configuration
}
}
Fetched April 11, 2026