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:
- Apollo Client - Type-safe apps with GraphQL-powered on-device caching (React, iOS, Kotlin)
- Apollo Connectors - Compose all your GraphQL and REST APIs into one GraphQL endpoint
- Apollo MCP Server - AI needs APIs. The fastest way to ship reliable AI experiences
- Apollo Router - Scale your APIs seamlessly with GraphQL Federation, Security, Auth, and more
- GraphOS - Deploy, manage, govern, and explore your APIs (start for free, no credit card needed)
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
🏆 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:
# macrobenchmarks
./gradlew -p benchmark :macrobenchmark:connectedBenchmarkAndroidTest
# microbenchmarks
./gradlew -p benchmark :microbenchmark:benchmarkReportInspiration
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:
- Parsing schema and operation documents into abstract syntax trees (ASTs)
- Providing input validation to raise warnings and errors (See the GraphQL spec)
- Support for outputting ASTs as valid, indented GraphQL documents
- Support for manipulation of ASTs via the
transformAPI
Installation
Add the apollo-ast dependency to your project:
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.
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():
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:
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
validateAsSchemamethod. - If the document represents one or more operations, call the
validateAsExecutablemethod.
`validateAsSchema`
validateAsSchema returns a GQLResult<Schema>. The following snippet parses and validates a short invalid schema that uses an undefined directive (@private):
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:
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:
[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:
// 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 childrenDelete: delete the nodeReplace(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:
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:
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:
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.
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 }:
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:
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:
// 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:
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:
mypackage.MyPluginThe 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:
// 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():
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:
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.