Launch GraphOS Studio

Queries in Apollo Kotlin

Fetching data in a predictable, type-safe way is one of the core features of . In this guide, you'll learn how to a endpoint and use the result in your application.


This page assumes some familiarity with building queries. For a refresher, we recommend reading this guide and practicing running queries in Apollo Sandbox.

Because uses standard syntax, anything you can run in Sandbox can also be put into .graphql files in your project.

This page also assumes that you've already set up for your Android/Kotlin application. For help with setup, see the getting started guide.


In , each you execute is represented as an instance of a generated class that implements the Query interface. To generate these classes, we first need to define the we want to execute.

Let's say we define a named HeroQuery, like so:

query HeroQuery($id: String!) {
hero(id: $id) {

If we define this in its own .graphql file, will generate a corresponding HeroQuery class that we can then use to execute the query.

To generate classes, requires your server's schema, along with all of the .graphql files that contain your defined . It uses these to generate code you can use to execute queries and access typed results.

All .graphql files in your project (or the subset you specify as input to apollo-codegen if you customize the script for your code generation build phase) are combined and treated as one . This means that defined in one .graphql file are available across all .graphql files. However, it also means that and names must be unique (and validation errors will occur if they aren't).


To execute the we just defined, we pass a HeroQuery instance to the query method of ApolloClient, like so:

val apolloClient = ApolloClient.Builder().serverUrl("https://your.domain/graphql").build()
val response = apolloClient.query(HeroQuery(id = "12")).execute()

By default, offloads I/O work to a background thread, which means it's safe to start on the main thread. The result is also dispatched to the calling thread, and you can use the response directly to update your data.

  • On the JVM, the I/O work is using Dispatchers.IO by default. You can change this dispatcher with ApolloClient.Builder.dispatcher.
  • On Kotlin/native (iOS, macOS, ...), the request offloads the cache and network I/O to background threads that resume in the main dispatch queue. For this reason, the ApolloClient APIs assume they are called from the main thread. It isn't possible to customize the dispatcher, but cache and network I/O are always done in background threads.


A 's results are returned as a hierarchy of immutable classes that match the structure of the query's . These classes only include that are included in the (other schema fields are omitted).

In other words, generates classes based on the queries you write, not based on the schema you against.

For example, given the following schema:

enum Episode { NEWHOPE, EMPIRE, JEDI }
interface Character {
id: String!
name: String!
friends: [Character]
appearsIn: [Episode]!

And the following :

query HeroAndFriendsNames {
hero {
friends {

generates a type-safe model that looks like this (details are omitted to focus on the class structure):

class HeroAndFriendsNamesQuery {
data class Data(val hero: Hero)
data class Hero(val name: String, friends: List<Friend>)
data class Friend(val id: String, val name: String)

Because the HeroAndFriendsNames doesn't fetch appearsIn, this property is not part of the returned result type and cannot be accessed here. Similarly, id is only accessible in Friend, not in Hero.

Because supports nullability, you have compiled-time type safety. If the request is successful, all queried data (and only this data) will be accessible. There is no need to handle null in UI code.


cancellation is handled via the CoroutineScope. Canceling the current scope cancels any associated ongoing .

Gradle plugin configuration
Edit on GitHubEditForumsDiscord

© 2024 Apollo Graph Inc.

Privacy Policy