apollo-kotlin Documentation

Rocket: Â A strongly-typed, caching GraphQL client for the JVM, Android, and Kotlin multiplatform.

3,954 stars Kotlin Kotlin 1 file · ~6,444 tokens #android#apollographql#graphql#graphql-client#kotlin
RAW Doc

1. Project Overview & Quickstart (apollographql/apollo-kotlin)

File: README.md

Apollo Kotlin

The industry-leading GraphQL client for Kotlin. Run on Android and all the Kotlin multiplatform targets. Apollo Kotlin delivers powerful caching, code generation, intuitive APIs, and comprehensive developer tools to accelerate your app development.

❓ Why Choose Apollo Kotlin?

✅ 100% type safety, from your server to your app, using code generation
✅ Intuitive, powerful caching - intelligent in-memory or SQLite caching out of the box
✅ Excellent support for modern Android and Kotlin Multiplatform apps
✅ Always up-to-date - we prioritize support for the latest versions of GraphQL, Kotlin, Gradle, and more
✅ GraphOS ready - turnkey support for Persisted Queries, and @defer
✅ Production-tested - Powers countless apps worldwide that serve millions of end users

🚀 Quick Start

If you are new to GraphQL, check out the tutorial that will guide you through building an Android app using Apollo.

For more in-depth documentation, head to the official documentation site.

For a detailed "Get Started" guide, check out our docs.

💡 Resources

Resource Description Link
Full Documentation Comprehensive guides and examples Read Docs →
API Reference Complete API documentation Browse Kdoc →
IntelliJ Plugin Enhanced development experience Install Plugin →
Free Course Learn GraphQL and Apollo Client Take Course →

🧑‍🚀 About Apollo

Deliver tomorrow's roadmap today with our comprehensive suite of API orchestration tools:

Explore the Complete Apollo Platform →

🛠️ Maintained by

Name Username
Benoit Lubek @bod
Jeff Auriemma @bignimbus
Martin Bonnin @martinbonnin

🗺️ Roadmap

We regularly update our public roadmap with the status of our work-in-progress and upcoming features.

📣 Tell us what you think

☑️ Apollo Kotlin User Survey
What do you like best about Apollo Kotlin? What needs to be improved? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo Kotlin usage and allow us to serve you better.

🗓️ Events

Join these live events to meet other GraphQL users and learn more:

🎪 Apollo Summit 2026
Oct 6-8, 2026 • San Francisco
1000+ engineers, talks, workshops, and office hours

View All Events →

🏆 Contributing

Thank you for your interest in submitting a Pull Request to Apollo Kotlin! Read our guidelines first, and don't hesitate to get in touch.

New to open source? Check out our Good First Issues to get started.

🤝 Code of Conduct

Please read our Code of Conduct. This applies to any space run by Apollo, including our GitHub repositories, the Apollo GraphOS Discord, the Apollo GraphQL Forum. The Code of Conduct reflects our commitment to making the Apollo Community a welcoming and safe space in which individuals can interact.

🪪 License

Source code in this repository is available under the terms of the MIT License. Read the full text here.


File: benchmark/app/README.md

A small app to monitor start performance and also to pass as an (unused) app apk to Firebase test labs for microbenchmarks.


File: benchmark/README.md

Benchmark

This is a standalone Android Studio project to benchmark performance.

Running the tests

You can run the tests from Android Studio by clicking the "run" icon in the gutter. This will
print the results in the Run window of Android Studio.

For the command line, use:

text
# macrobenchmarks
./gradlew -p benchmark :macrobenchmark:connectedBenchmarkAndroidTest 

# microbenchmarks
./gradlew -p benchmark :microbenchmark:benchmarkReport

Inspiration

The largesample Json parsing data is taken from https://zacsweers.github.io/json-serialization-benchmarking/.
The calendar_response data was provided by @sebj and is a real-life use case.
The tracks data is inspired by the Deezer API.

Current results:

You can get the current results at https://github.com/apollographql/apollo-kotlin/issues/4231


File: build-logic/README.md

build-logic

A simple JVM project that contains the shared build logic.

It also contains all the buildscript dependencies so that we don't have to specify versions in each module plugins {} block.


File: design-docs/Readme.md

Design docs

This is Apollo Kotlin documentation for how things work under the hood. The user-facing documentation about how to use Apollo Kotlin is available at https://www.apollographql.com/docs/android/.

This internal documentation is work in progress. It is used for brainstorming/communication but might be lagging sometimes, feel free to send PRs!


File: docs/source/advanced/apollo-ast.mdx


title: Apollo AST

To generate client code, Apollo Kotlin parses both your GraphQL schema and each operation you write against it into an Abstract Syntax Tree (AST). An AST represents a GraphQL document in a type-safe, machine-readable format.

The Apollo Kotlin parser has its own artifact (apollo-ast), which you can use independently of apollo-runtime or apollo-api.

Features of apollo-ast include:

Installation

Add the apollo-ast dependency to your project:

kotlin title="build.gradle[.kts]"
dependencies {
  // ...

  implementation("com.apollographql.apollo:apollo-ast:5.1.0")
}

Parsing a document

Use the parseAsGQLDocument method to parse a document from a File, a String, or an Okio BufferedSource.

kotlin {13}
val graphQLText = """
    query HeroForEpisode(${"$"}ep: Episode) {
      hero(episode: ${"$"}ep) {
        name
        friends {
          height
        }
        foobar
      }
    }
""".trimIndent()

val parseResult = graphQLText.parseAsGQLDocument()

This method returns a GQLResult<GQLDocument>, which contains the document and/or parsing issues, each of which can have a severity of either WARNING or ERROR. Because there can be warnings, it is possible to have both a valid document and issues at the same time.

To get the document and throw on errors, use getOrThrow():

kotlin
val queryGqlDocument = parseResult.getOrThrow()

GQLDocument is the root of the AST. It contains a list of GQLDefinitions that together represent the GraphQL document.

All nodes in an AST are subclasses of GQLNode (all named with the GQL prefix). Each subclass exposes specific properties and methods relevant to the corresponding node type.

Example AST structure

In the HeroForEpisode example above, here's the structure of the AST returned by the parser:

text
GQLDocument
    └─GQLOperationDefinition query "HeroForEpisode"
        ├─GQLVariableDefinition "ep": "Episode"
        └─GQLSelectionSet
            └─GQLField "hero"
                ├─GQLSelectionSet
                │   ├─GQLField "name"
                │   ├─GQLField "friends"
                │   │   └─GQLSelectionSet
                │   │       └─GQLField "height"
                │   └─GQLField "foobar"
                └─GQLArguments
                    └─GQLArgument "episode"
                        └─GQLVariableValue "ep"

Note that this structure and its node names closely follow the GraphQL specification.

Validating input

In addition to parsing, the apollo-ast library provides methods to perform higher-level validation of GraphQL documents.

To validate a parsed GQLDocument:

  • If the document represents a schema, call the validateAsSchema method.
  • If the document represents one or more operations, call the validateAsExecutable method.

`validateAsSchema`

validateAsSchema returns a GQLResult<Schema>. The following snippet parses and validates a short invalid schema that uses an undefined directive (@private):

kotlin {11,19}
val schemaText = """
    type Query {
      hero(episode: Episode): Character
    }

    enum Episode {
      NEWHOPE
      EMPIRE
    }

    type Character @private {
      name: String
      height: Int @deprecated
      friends: [Character]
    }
""".trimIndent()

val schemaGQLDocument = schemaText.parseAsGQLDocument().getOrThrow()
val schemaResult = schemaGQLDocument.validateAsSchema()
println(schemaResult.issues.map { it.severity.name + ": " + it.message })

When executed, this snippet prints [WARNING: Unknown directive 'private'].

Because this is a warning and not an error, you can still use the returned schemaResult.getOrThrow()

`validateAsExecutable`

The validateAsExecutable method checks whether a document's defined operations are valid against a particular provided Schema. You can obtain this Schema parameter by calling the above validateAsSchema on the GQLDocument that represents the schema:

kotlin
val schema = schemaGQLDocument.validateAsSchema().getOrThrow()
val executableIssues = queryGqlDocument.validateAsExecutable(schema)
println(executableIssues.map { it.severity.name + ": " + it.message })

If the queryGqlDocument queries a deprecated field and misspells another, this snippet might print the following:

text
[WARNING: Use of deprecated field 'height', ERROR: Can't query 'frends' on type 'Character']

Outputting SDL

You can output a GQLDocument to standard GraphQL syntax with the toUtf8 extensions:

kotlin
// Returns a string
println(queryGqlDocument.toUtf8())

// Output to a File
queryGqlDocument.toUtf8(file)

Transforming an AST

You can use the transform method of GQLDocument to modify an existing AST.

You pass transform a lambda that accepts a GQLNode and also returns instructions to manipulate the AST:

  • Continue: keep the node as-is and continue visiting the children
  • Delete: delete the node
  • Replace(GQLNode): replace the node with the given one

The transform method traverses the AST and executes the lambda for each node, then acts on the AST according to the lambda's return value.

Note that with Delete and Replace, the node's children are not visited automatically, so you should call transform
recursively if that is needed.

For example, this snippet removes all fields named restrictedField from operations defined in queryGqlDocument and prints the result:

kotlin
val transformedQuery = queryGqlDocument.transform{ node ->
  if (node is GQLField && node.name == "restrictedField") {
    TransformResult.Delete
  } else {
    TransformResult.Continue
  }
}
println(transformedQuery!!.toUtf8())

File: docs/source/advanced/authentication.mdx


title: Authenticate your operations

Authentication is not included in the GraphQL specification. This page aims at giving some guidance for the most common scenarios but doesn't intend to be exhaustive.

Authenticating your HTTP requests with OkHttp

OkHttp Interceptors are an easy way to add an "Authorization" header to your HTTP requests.

OkHttp Interceptors have been around for a long time and work well but can only be used with Apollo Kotlin on Android and the JVM.

Authenticating your HTTP requests with Apollo HttpInterceptor

To authenticate your HTTP requests in a multi-platform way, you can use an Apollo HttpInterceptor.

HttpInterceptor is multiplatform and uses an API very similar to OkHttp's:

kotlin
class AuthorizationInterceptor() : HttpInterceptor {
  private val mutex = Mutex()

  override suspend fun intercept(request: HttpRequest, chain: HttpInterceptorChain): HttpResponse {
    var token = mutex.withLock {
      // get current token
    }

    val response = chain.proceed(request.newBuilder().addHeader("Authorization", "Bearer $token").build())

    return if (response.statusCode == 401) {
      token = mutex.withLock {
        // get new token
      }
      chain.proceed(request.newBuilder().addHeader("Authorization", "Bearer $token").build())
    } else {
      response
    }
  }
}

For a more advanced example, you can take a look at the AuthorizationInterceptor integration tests

Authenticate your subscriptions with an HTTP header or query parameter

ApolloClient creates different WebSockets for different header values. Use an interceptor to change the header value on error:

kotlin
private class UpdateAuthorizationHeaderInterceptor : ApolloInterceptor {
  @OptIn(ExperimentalCoroutinesApi::class)
  override fun <D : Operation.Data> intercept(request: ApolloRequest<D>, chain: ApolloInterceptorChain): Flow<ApolloResponse<D>> {
    return flow {
      // Retrieve a new access token every time
      val request = if (request.operation is Subscription<*>) {
        request.newBuilder()
            // Update the HTTP header
            .addHttpHeader("Authorization", "Bearer ${accessToken()}")
            // Or change the url
            .url("https://example.com/subscription?token=${accessToken()}")
            .build()
      } else {
        request
      }

      emitAll(chain.proceed(request))
    }
  }
}

Note: The client shares WebSockets in a pool. If your access token changes frequently, the client might open multiple WebSockets concurrently.

Authenticate your subscriptions with a connection payload

The connection payload is specific to the WsProtocol. Pass a lambda to the WsProtocol constructor that the client evaluates whenever it creates a WebSocket.

kotlin
ApolloClient.Builder()
  .httpServerUrl(mockServer.url())
  .subscriptionNetworkTransport(
      WebSocketNetworkTransport.Builder()
          .serverUrl(mockServer.url())
          .wsProtocol(GraphQLWsProtocol(
              connectionPayload = {
                getFreshConnectionPayload()
              }
          ))
          .build()
  )
  .build()

Retry your subscriptions automatically

The preceding approaches require your backend to indicate when a token expires. Unlike HTTP 401 errors, WebSockets lack a widespread standard for expiration signaling.

If your backend closes the WebSocket, retry subscriptions automatically using retryOnError { it.operation is Subscription }:

kotlin
ApolloClient.Builder()
  .serverUrl(mockServer.url())
  .retryOnError { it.operation is Subscription }

For other cases, customize your RetryStrategy. For details, see Network errors.


File: docs/source/advanced/client-awareness.mdx


title: Client Awareness

GraphOS Studio users can opt in Client Awareness. Client Awareness allows you to view operation metrics split per client, helping you understand how each one interacts with your graph.

Client Awareness uses apollographql-client-name and apollographql-client-version custom HTTP headers to report client usage.

Enable it by adding an ApolloClientAwarenessInterceptor to your ApolloClient:

kotlin
val apolloClient = ApolloClient.Builder()
    .serverUrl("https://example.com/graphql")
    .addHttpInterceptor(ApolloClientAwarenessInterceptor(BuildConfig.APPLICATION_ID, BuildConfig.VERSION_NAME))
    .build()

This example uses BuildConfig to set the app's applicationId as the client name and its versionName as the client version, but you can override this. Especially, if your iOS and Android apps use the same package name, it's useful to customize it to be able to differentiate the clients.


File: docs/source/advanced/compiler-plugins.mdx


title: Apollo compiler plugins

Compiler plugins are currently experimental in Apollo Kotlin. If you have feedback on them, please let us know via GitHub issues or in the Kotlin Slack community.

The Apollo compiler supports a wide range of options. For the cases where these options are not enough, you can use Apollo compiler plugins to modify the behaviour of the compiler.

Apollo compiler plugins allow to:

  • Change the layout of the generated sources (name of the classes, package names, capitalization rules).
  • Change the ids of operation for persisted queries.
  • Transform the JavaPoet/KotlinPoet models.
  • Transform the Apollo IR.

Implementing a compiler plugin

In this example we will implement a plugin that uses custom persisted queries ids registered on your backend.

The Apollo compiler use the ServiceLoader API to load plugins at runtime. Plugins need to be implemented in a separate module that is added to the classpath.

To start, create a new Gradle module and add apollo-compiler as a dependency to the module build.gradle[.kts] file. In this example, we'll use apollo-compiler-plugin as module name:

kotlin
// apollo-compiler-plugin/build.gradle.kts
plugins {
  id("org.jetbrains.kotlin.jvm")
}

dependencies {
  // Add apollo-compiler as a compileOnly dependency
  compileOnly("com.apollographql.apollo:apollo-compiler:5.1.0")  
}

Next create your plugin in a src/main/kotlin/mypackage/MyPlugin file:

kotlin
class MyPlugin: ApolloCompilerPlugin {
  override fun beforeCompilationStep(
      environment: ApolloCompilerPluginEnvironment,
      registry: ApolloCompilerRegistry,
  ) {
    // add your custom code here
  }
}

Make your plugin discoverable by ServiceLoader by adding a resource in src/main/resources/META-INF/services/com.apollographql.apollo.compiler.ApolloCompilerPlugin. This file contains the fully qualified name of your plugin:

text
mypackage.MyPlugin

The name of the resource file is important. It must be com.apollographql.apollo.compiler.ApolloCompilerPlugin and be in the META-INF/services folder. This is how ServiceLoader looks up plugins at runtime.

Adding a plugin to the Apollo compiler classpath

Use the Service.plugin() Gradle method to add the plugin to the Apollo compiler classpath:

kotlin
// app/build.gradle.kts
plugins {
  id("org.jetbrains.kotlin.jvm")
  id("com.apollographql.apollo")
}

apollo {
  service("service") {
    packageName.set("com.example")
    
    // Add your plugin to the Apollo compiler classpath
    plugin(project(":apollo-compiler-plugin")) // highlight-line
  }
}

The plugin code will now be invoked the next time the compiler is invoked.

Passing arguments to your Apollo compiler plugin

Because the compiler plugin runs in an isolated classpath, you can't use classes or data from your main build logic classpath.

In order to pass build-time arguments to your Apollo compiler plugin, use pluginArgument():

kotlin
apollo {
  service("service") {
    packageName.set("com.example")
    
    // Add your plugin to the Apollo compiler classpath
    plugin(project(":apollo-compiler-plugin"))
    // Add argument
    pluginArgument("com.example.token", token) // highlight-line
  }
}

Note that arguments are shared between all compiler plugins and using a prefix such as your plugin package name is recommended to avoid name clashes.

The arguments are available in ApolloCompilerPluginEnvironment.arguments:

kotlin
class MyPlugin: ApolloCompilerPlugin {
  override fun beforeCompilationStep(
      environment: ApolloCompilerPluginEnvironment,
      registry: ApolloCompilerRegistry,
  ) {
    val token = environment.arguments.get("token") as String
    
    // add your custom code here
  }
}

Arguments must be serializable and be instances of classes accessible from the bootstrap classloader. In practice, built-in types and collections are supported.

Other references

For other plugin APIs like layout, IR, JavaPoet and KotlinPoet transforms, check out the ApolloCompilerPlugin API docs

For more examples, check out the integration-tests.

2. Official Technical Reference & Guides (apollographql/docs)

This repository contains an archived version of the documentation platform for the Apollo Documentation site. It is no longer actively maintained, and the content here may be outdated. The project has undergone significant updates, and the latest documentation platform is now maintained in a private repository.

To update documentation content for Apollo’s open-source and source-available SDKs and libraries, you can submit pull requests to the relevant repository:

To submit feedback about the documentation, please use the Give Feedback option at the bottom of documentation content pages.