Repository: apollographql/apollo-kotlin
Pull request #4702 (2023-02-22 16:45:50)

Include deprecated arguments and directives in introspection
See #4699

netlify[bot]: ### <span aria-hidden="true">👷</span> Deploy Preview for *apollo-android-docs* processing.


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 0f408843b47d613efd0af57c18a9b58cce1a5a4e |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/apollo-android-docs/deploys/63f646c0330cfb0008bb4af6 |

Patch:
diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml
index ab3250946f..7cfd1046d5 100644
--- a/.github/workflows/benchmarks.yml
+++ b/.github/workflows/benchmarks.yml
@@ -15,7 +15,7 @@ jobs:
       - uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b #v3.9.0
         with:
           distribution: 'temurin'
-          java-version: '11'
+          java-version: 17
       - uses: gradle/gradle-build-action@3fbe033aaae657f011f88f29be9e65ed26bd29ef #v2.3.3
       - run: |
           ulimit -c unlimited
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index c59310bad5..cf41a7f394 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -19,7 +19,7 @@ jobs:
       - uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b #v3.9.0
         with:
           distribution: 'temurin'
-          java-version: 11
+          java-version: 17
       - uses: gradle/gradle-build-action@3fbe033aaae657f011f88f29be9e65ed26bd29ef #v2.3.3
       - name: Build with Gradle
         run: |
@@ -45,7 +45,7 @@ jobs:
       - uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b #v3.9.0
         with:
           distribution: 'temurin'
-          java-version: 11
+          java-version: 11 # Keep this one on an older JDK version to make sure we can still build with Java11
       - uses: gradle/gradle-build-action@3fbe033aaae657f011f88f29be9e65ed26bd29ef #v2.3.3
       - name: Build with Gradle
         run: |
@@ -71,7 +71,7 @@ jobs:
       - uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b #v3.9.0
         with:
           distribution: 'temurin'
-          java-version: 11
+          java-version: 17
       - uses: gradle/gradle-build-action@3fbe033aaae657f011f88f29be9e65ed26bd29ef #v2.3.3
       - name: Build with Gradle
         run: |
@@ -113,7 +113,7 @@ jobs:
         uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b #v3.9.0
         with:
           distribution: 'temurin'
-          java-version: 11
+          java-version: 17
 
       # Set environment variables
       - name: Export Properties
diff --git a/.github/workflows/publish-ij-plugin-snapshot.yml b/.github/workflows/publish-ij-plugin-snapshot.yml
index 51938438dd..8e52f91b66 100644
--- a/.github/workflows/publish-ij-plugin-snapshot.yml
+++ b/.github/workflows/publish-ij-plugin-snapshot.yml
@@ -16,7 +16,7 @@ jobs:
       - uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b #v3.9.0
         with:
           distribution: 'temurin'
-          java-version: 11
+          java-version: 17
 
       - name: Increment snapshot version
         run: |
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index cc5a347919..0b654b1bac 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -16,7 +16,7 @@ jobs:
       - uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b #v3.9.0
         with:
           distribution: 'temurin'
-          java-version: '11'
+          java-version: 17
       - uses: gradle/gradle-build-action@3fbe033aaae657f011f88f29be9e65ed26bd29ef #v2.3.3
       - name: Build with Gradle
         run: |
@@ -28,7 +28,6 @@ jobs:
           ./gradlew --no-build-cache ciBuild
           ./gradlew --stop
           ./gradlew --no-build-cache -p tests ciBuild
-          ./gradlew --no-build-cache dokkaHtmlMultiModule
           ./gradlew --no-build-cache ciPublishSnapshot
         env:
           SONATYPE_NEXUS_PASSWORD: ${{ secrets.SONATYPE_NEXUS_PASSWORD }}
@@ -42,8 +41,3 @@ jobs:
         with:
           name: push.zip
           path: push.zip
-      - name: Deploy Kdoc to github pages
-        uses: JamesIves/github-pages-deploy-action@ba1486788b0490a235422264426c45848eac35c6 #v4.4.1
-        with:
-          branch: gh-pages # The branch the action should deploy to.
-          folder: build/dokkaHtml # The folder the action should deploy.
diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml
index b45214d721..8b944431f6 100644
--- a/.github/workflows/tag.yml
+++ b/.github/workflows/tag.yml
@@ -15,7 +15,7 @@ jobs:
       - uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b #v3.9.0
         with:
           distribution: 'temurin'
-          java-version: 11
+          java-version: 17
       - uses: gradle/gradle-build-action@3fbe033aaae657f011f88f29be9e65ed26bd29ef #v2.3.3
       - name: Publish to Maven Central
         run: |
@@ -35,7 +35,7 @@ jobs:
       - uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b #v3.9.0
         with:
           distribution: 'temurin'
-          java-version: 11
+          java-version: 17
       - name: Publish to JetBrains marketplace
         run: ./gradlew --no-build-cache :intellij-plugin:publishPlugin
         env:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ec2a6b61e0..36494d99b5 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -113,6 +113,8 @@ We usually favor Builders for reasons outlined in [this issue](https://github.co
 * For expect/actual, it's sometime convenient to expose an interface even if it's not intended to be subclassed by
   callers like `MockServerInterface`. In that case, it's ok to use `FooInterface` for the interface and `Foo()` for the
   implementation to avoid having "DefaultFoo" everywhere when there's only one "Foo".
+* Builders may open the door to bad combination of arguments. This is ok. In that case, they should be detected at
+  runtime and fail fast by throwing an exception.
 
 Java interop
 
@@ -134,7 +136,7 @@ Logging & Error messages
 * Apollo Kotlin must not log anything to System.out or System.err
 * Error messages are passed to the user through `Exception.message`
 * For debugging logs, APIs are provided to get diagnostics (like CacheMissException, HttpInfo, ...). APIs are better
-  defined and allow more fine-grained diagnostics.
+  defined and allow more fine-grained diagnostics. See  https://publicobject.com/2022/05/01/eventlisteners-are-good/
 * There is one exception for the Gradle plugin. It is allowed to log information though the lifecycle() methods.
 * Messages should contain "Apollo: " when it's not immediately clear that the message comes from Apollo.
 
diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts
index cc60c830a9..41ca54b984 100644
--- a/build-logic/build.gradle.kts
+++ b/build-logic/build.gradle.kts
@@ -1,3 +1,4 @@
+import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
 import org.jetbrains.kotlin.samWithReceiver.gradle.SamWithReceiverExtension
 import org.jetbrains.kotlin.samWithReceiver.gradle.SamWithReceiverGradleSubplugin
 
@@ -50,9 +51,15 @@ dependencies {
   runtimeOnly(golatac.lib("kotlinx.binarycompatibilityvalidator"))
 }
 
+// Keep in sync with CompilerOptions.kt
 java {
-  // Keep in sync with CompilerOptions.kt
-  toolchain.languageVersion.set(JavaLanguageVersion.of(11))
+  toolchain.languageVersion.set(JavaLanguageVersion.of(17))
+}
+tasks.withType<JavaCompile>().configureEach {
+  options.release.set(11)
+}
+tasks.withType(KotlinJvmCompile::class.java).configureEach {
+  kotlinOptions.jvmTarget = "11"
 }
 
 gradlePlugin {
diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts
index 4515fa727b..1f633c69ca 100644
--- a/build-logic/settings.gradle.kts
+++ b/build-logic/settings.gradle.kts
@@ -1,3 +1,7 @@
+plugins {
+  id("org.gradle.toolchains.foojay-resolver-convention") version "0.4.0"
+}
+
 rootProject.name = "build-logic"
 
 apply(from = "../gradle/repositories.gradle.kts")
diff --git a/build-logic/src/main/kotlin/CompilerOptions.kt b/build-logic/src/main/kotlin/CompilerOptions.kt
index 2542892d56..fddbe4d25c 100644
--- a/build-logic/src/main/kotlin/CompilerOptions.kt
+++ b/build-logic/src/main/kotlin/CompilerOptions.kt
@@ -1,7 +1,9 @@
 import org.gradle.api.Project
 import org.gradle.api.plugins.JavaPluginExtension
 import org.gradle.api.tasks.compile.JavaCompile
+import org.gradle.api.tasks.testing.Test
 import org.gradle.jvm.toolchain.JavaLanguageVersion
+import org.gradle.jvm.toolchain.JavaToolchainService
 import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
 import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
 import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
@@ -46,9 +48,8 @@ fun Project.configureJavaAndKotlinCompilers() {
 
   @Suppress("UnstableApiUsage")
   project.extensions.getByType(JavaPluginExtension::class.java).apply {
-    // Compile and run tests with Java11
     // Keep in sync with build-logic/build.gradle.kts
-    toolchain.languageVersion.set(JavaLanguageVersion.of(11))
+    toolchain.languageVersion.set(JavaLanguageVersion.of(17))
   }
   @Suppress("UnstableApiUsage")
   project.tasks.withType(JavaCompile::class.java).configureEach {
@@ -59,6 +60,15 @@ fun Project.configureJavaAndKotlinCompilers() {
   allWarningsAsErrors(true)
 }
 
+fun Project.configureTests(jvmVersion: Int) {
+  tasks.withType(Test::class.java).configureEach {
+    val javaToolchains = this@configureTests.extensions.getByName("javaToolchains") as JavaToolchainService
+    javaLauncher.set(javaToolchains.launcherFor {
+      languageVersion.set(JavaLanguageVersion.of(jvmVersion))
+    })
+  }
+}
+
 internal fun Project.optIn(vararg annotations: String) {
   tasks.withType(KotlinCompile::class.java).configureEach {
     kotlinOptions {
diff --git a/build-logic/src/main/kotlin/com/apollographql/apollo3/buildlogic/plugin/LibraryConventionPlugin.kt b/build-logic/src/main/kotlin/com/apollographql/apollo3/buildlogic/plugin/LibraryConventionPlugin.kt
index db79c9e11d..32a8a0e5e8 100644
--- a/build-logic/src/main/kotlin/com/apollographql/apollo3/buildlogic/plugin/LibraryConventionPlugin.kt
+++ b/build-logic/src/main/kotlin/com/apollographql/apollo3/buildlogic/plugin/LibraryConventionPlugin.kt
@@ -4,6 +4,7 @@ import configureJavaAndKotlinCompilers
 import configureMppDefaults
 import configurePublishing
 import configureTesting
+import configureTests
 import optIn
 import org.gradle.api.Action
 import org.gradle.api.Plugin
@@ -18,7 +19,7 @@ class LibraryConventionPlugin : Plugin<Project> {
       group = property("GROUP")!!
       version = property("VERSION_NAME")!!
 
-      extensions.create("apolloLibrary", Extension::class.java)
+      extensions.create("apolloLibrary", Extension::class.java, project)
 
       configureJavaAndKotlinCompilers()
       optIn(
@@ -58,5 +59,9 @@ class LibraryConventionPlugin : Plugin<Project> {
         }
       }
     }
+
+    fun runTestsWithJavaVersion(javaVersion: Int) {
+      project.configureTests(javaVersion)
+    }
   }
 }
diff --git a/docs/source/essentials/errors.mdx b/docs/source/essentials/errors.mdx
index be07b37c68..0e056d5418 100644
--- a/docs/source/essentials/errors.mdx
+++ b/docs/source/essentials/errors.mdx
@@ -10,26 +10,21 @@ Whenever you execute a GraphQL operation with Apollo Kotlin (or any other GraphQ
 
 ## Network errors
 
-When calling `execute()`, network errors throw an `ApolloException`. To handle them, wrap your query in a `try/catch` block:
+Network errors are surfaced in the `ApolloResponse.exception` field.
 
 ```kotlin
-try {
-  val response = apolloClient.query(query).execute()
-} catch(exception: ApolloException) {
+val response = apolloClient.query(query).execute()
+if (response.exception != null) {
   // handle exception here
 }
 ```
 
-When using `toFlow()` (e.g. with [subscriptions](../essentials/subscription)) and `watch()` (with the [normalized cache](../caching/query-watchers)), network errors are emitted in `ApolloResponse.exception`.
+This is also true when calling `toFlow()` (e.g. with [subscriptions](../essentials/subscription)) and `watch()` (with the [normalized cache](../caching/query-watchers)).
 
 ```kotlin
-apolloClient.query(query).toFlow().collect { response ->
+apolloClient.subscription(subscription).toFlow().collect { response ->
   if (response.exception != null) {
     // handle network errors
-  } else if (response.hasErrors()) {
-    // handle GraphQL errors
-  } else {
-    // no errors, handle data
   }
 }
 ```
@@ -98,11 +93,10 @@ Note that while there are errors, the query successfully returned the title of t
 Apollo Kotlin gives you access to both the data and the errors in the `Response` class:
 
 ```kotlin
-val response = try {
-  apolloClient.query(query).execute()
-} catch(exception: ApolloException) {
+val response = apolloClient.query(query).execute()
+if (response.exception != null) {
   // Network error, not much to do
-  throw exception
+  throw response.exception
 }
 
 // It's possible to display the film title
@@ -122,10 +116,10 @@ if (person != null) {
 
 If you don't want to handle partial responses, you can simplify your error handling logic. `ApolloResponse.dataAssertNoErrors` returns a non-nullable `data` and throws if there are any errors. This way, you can handle all errors in a single `catch {}` block:
 
-```
+```kotlin
 val data = try {
   apolloClient.query(query).execute().dataAssertNoErrors
-} catch(exception: ApolloException) {
+} catch (exception: ApolloException) {
   // All network or GraphQL errors are handled here
   throw exception
 }
diff --git a/docs/source/essentials/mutations.mdx b/docs/source/essentials/mutations.mdx
index c535eeb3f7..ef0e7bbd81 100644
--- a/docs/source/essentials/mutations.mdx
+++ b/docs/source/essentials/mutations.mdx
@@ -63,11 +63,7 @@ to `ApolloClient#mutation(mutation)` to send the mutation to the server, execute
 ```kotlin
 val upvotePostMutation = UpvotePostMutation(postId = 3)
 
-val response = try {
-  apolloClient.mutation(upvotePostMutation).execute()
-} catch(e: ApolloException) {
-  // handle error
-}
+val response = apolloClient.mutation(upvotePostMutation).execute()
 ```
 
 ## Using fragments in mutation results
@@ -98,9 +94,5 @@ mutation CreateReviewForEpisode($episode: Episode!, $review: ReviewInput!) {
 ```kotlin
 val reviewInput = ReviewInput(stars = 5, commentary = "This is a great movie!")
 
-try {
-  val response = apolloClient.mutation(CreateReviewForEpisodeMutation(episode = Episode.NEWHOPE, review = reviewInput)).execute()
-} catch (e: ApolloException) {
-  // handle exception
-}
+val response = apolloClient.mutation(CreateReviewForEpisodeMutation(episode = Episode.NEWHOPE, review = reviewInput)).execute()
 ```
diff --git a/docs/source/migration/4.0.mdx b/docs/source/migration/4.0.mdx
index ee9de853a8..3de029d910 100644
--- a/docs/source/migration/4.0.mdx
+++ b/docs/source/migration/4.0.mdx
@@ -3,5 +3,79 @@ title: Migrating to Apollo Kotlin 4.0
 description: From 3.x
 ---
 
+> Note: this page is a work in progress.
+
 * Requires Kotlin Gradle Plugin 1.6 (from 1.5)
 * Dropped `enableCompatibilityMetadataVariant`
+* Configuring your cache after enabling APQs will now fail (see https://github.com/apollographql/apollo-kotlin/pull/4709)
+
+## Error handling
+
+### Exception surfacing
+
+In v3, non-GraphQL errors like network errors, cache misses, and WebSocket protocol errors were surfaced by throwing exceptions in `ApolloCall.execute()` and in Flows (`ApolloCall.toFlow()`, `ApolloCall.watch()`). This was not ideal because it was a difference in how to handle GraphQL errors vs other errors. Moreover, throwing terminates a Flow and consumers would have to handle re-collection.
+
+In v4, a field `ApolloResponse.exception` has been added and these errors are now surfaced by returning (for `execute()`) or emitting (for Flows) an `ApolloResponse` with a non null `exception` instead of throwing it. This allows consumers to handle different kinds of errors at the same place, and it avoids Flows from being terminated. 
+
+To ease the migration to v4, the v3 behavior can be restored by calling `ApolloClient.Builder.useV3ExceptionHandling(true)`.
+
+```kotlin
+// Replace
+try {
+  val response = client.query(MyQuery()).execute()
+  if (response.hasErrors()) {
+    // Handle GraphQL errors
+  }
+} catch (e: ApolloException) {
+  // Handle network error
+}
+
+// With
+val response = client.query(MyQuery()).execute()
+if (response.exception != null) {
+  // Handle network error
+} else if (response.hasErrors()) {
+  // Handle GraphQL errors
+}
+
+// Replace
+client.subscription(MySubscription()).toFlow().collect { response ->
+  if (response.hasErrors()) {
+    // Handle GraphQL errors
+  }
+}.catch { e ->
+  // Handle network error
+}
+
+// With
+client.subscription(MySubscription()).toFlow().collect { response ->
+  if (response.exception != null) {
+    // Handle network error
+  } else if (response.hasErrors()) {
+    // Handle GraphQL errors
+  }
+}
+```
+
+### Exception folding when using the cache
+
+In v3, when using the normalized cache, you could set `emitCacheMisses` to `true` to emit cache misses instead of throwing.
+
+In v4, this is now the default behavior and `emitCacheMisses` has been removed. 
+With the `CacheFirst`, `NetworkFirst` and `CacheAndNetwork` policies, cache misses and network errors are now emitted in `ApolloResponse.exception`.
+
+To ease the migration to v4, the v3 behavior can be restored by by calling `ApolloClient.Builder.useV3ExceptionHandling(true)`.
+
+### Exceptions in `watch`
+
+In v3, `ApolloCall.watch()` would accept a `fetchThrows` and `refetchThrows` parameters to control whether to throw cache or network exceptions happening during the initial fetch or subsequent refetches, the default value being `false`.
+
+In v4, these exceptions are now emitted in `ApolloResponse.exception`.
+
+If they are undesirable, ignore them by filtering them out:
+
+```kotlin   
+client.query(MyQuery()).watch().filter { it.exception == null }.collect { response ->
+  // Handle responses
+}
+```
diff --git a/intellij-plugin/gradle.properties b/intellij-plugin/gradle.properties
index e4a99e3452..509bbd0568 100644
--- a/intellij-plugin/gradle.properties
+++ b/intellij-plugin/gradle.properties
@@ -30,4 +30,4 @@ javaVersion=17
 kotlin.stdlib.default.dependency=false
 
 # Snapshot version, automatically incremented by the CI
-snapshotVersion=6
+snapshotVersion=7
diff --git a/intellij-plugin/snapshots/plugins.xml b/intellij-plugin/snapshots/plugins.xml
index 018e6a1862..7f81cdb3f2 100644
--- a/intellij-plugin/snapshots/plugins.xml
+++ b/intellij-plugin/snapshots/plugins.xml
@@ -1,8 +1,8 @@
 <plugins>
   <plugin
       id="com.apollographql.ijplugin"
-      url="https://repsy.io/mvn/bod/apollo-intellij-plugin/com/apollographql/apollo-intellij-plugin/4.0.0-SNAPSHOT.6/apollo-intellij-plugin-4.0.0-SNAPSHOT.6.zip"
-      version="4.0.0-SNAPSHOT.6">
+      url="https://repsy.io/mvn/bod/apollo-intellij-plugin/com/apollographql/apollo-intellij-plugin/4.0.0-SNAPSHOT.7/apollo-intellij-plugin-4.0.0-SNAPSHOT.7.zip"
+      version="4.0.0-SNAPSHOT.7">
     <idea-version since-build="222" until-build="231.*"/>
     <name>Apollo GraphQL (Snapshot)</name>
   </plugin>
diff --git a/libraries/apollo-api/api/apollo-api.api b/libraries/apollo-api/api/apollo-api.api
index 098e532443..98d95ad31e 100644
--- a/libraries/apollo-api/api/apollo-api.api
+++ b/libraries/apollo-api/api/apollo-api.api
@@ -168,10 +168,13 @@ public abstract class com/apollographql/apollo3/api/BTerm {
 
 public final class com/apollographql/apollo3/api/BVariable : com/apollographql/apollo3/api/BTerm {
 	public fun <init> (Ljava/lang/String;)V
+	public fun <init> (Ljava/lang/String;Ljava/lang/Boolean;)V
 	public final fun component1 ()Ljava/lang/String;
-	public final fun copy (Ljava/lang/String;)Lcom/apollographql/apollo3/api/BVariable;
-	public static synthetic fun copy$default (Lcom/apollographql/apollo3/api/BVariable;Ljava/lang/String;ILjava/lang/Object;)Lcom/apollographql/apollo3/api/BVariable;
+	public final fun component2 ()Ljava/lang/Boolean;
+	public final fun copy (Ljava/lang/String;Ljava/lang/Boolean;)Lcom/apollographql/apollo3/api/BVariable;
+	public static synthetic fun copy$default (Lcom/apollographql/apollo3/api/BVariable;Ljava/lang/String;Ljava/lang/Boolean;ILjava/lang/Object;)Lcom/apollographql/apollo3/api/BVariable;
 	public fun equals (Ljava/lang/Object;)Z
+	public final fun getDefaultValue ()Ljava/lang/Boolean;
 	public final fun getName ()Ljava/lang/String;
 	public fun hashCode ()I
 	public fun toString ()Ljava/lang/String;
@@ -286,11 +289,14 @@ public final class com/apollographql/apollo3/api/CompiledArgument$Builder {
 
 public final class com/apollographql/apollo3/api/CompiledCondition {
 	public fun <init> (Ljava/lang/String;Z)V
+	public fun <init> (Ljava/lang/String;ZZ)V
 	public final fun component1 ()Ljava/lang/String;
 	public final fun component2 ()Z
-	public final fun copy (Ljava/lang/String;Z)Lcom/apollographql/apollo3/api/CompiledCondition;
-	public static synthetic fun copy$default (Lcom/apollographql/apollo3/api/CompiledCondition;Ljava/lang/String;ZILjava/lang/Object;)Lcom/apollographql/apollo3/api/CompiledCondition;
+	public final fun component3 ()Z
+	public final fun copy (Ljava/lang/String;ZZ)Lcom/apollographql/apollo3/api/CompiledCondition;
+	public static synthetic fun copy$default (Lcom/apollographql/apollo3/api/CompiledCondition;Ljava/lang/String;ZZILjava/lang/Object;)Lcom/apollographql/apollo3/api/CompiledCondition;
 	public fun equals (Ljava/lang/Object;)Z
+	public final fun getDefaultValue ()Z
 	public final fun getInverted ()Z
 	public final fun getName ()Ljava/lang/String;
 	public fun hashCode ()I
diff --git a/libraries/apollo-api/src/commonMain/kotlin/com/apollographql/apollo3/api/BooleanExpression.kt b/libraries/apollo-api/src/commonMain/kotlin/com/apollographql/apollo3/api/BooleanExpression.kt
index cdc23b71c2..4357f17c3a 100644
--- a/libraries/apollo-api/src/commonMain/kotlin/com/apollographql/apollo3/api/BooleanExpression.kt
+++ b/libraries/apollo-api/src/commonMain/kotlin/com/apollographql/apollo3/api/BooleanExpression.kt
@@ -136,7 +136,9 @@ sealed class BTerm
 /**
  * A term that comes from @include/@skip or @defer directives and that needs to be matched against operation variables
  */
-data class BVariable(val name: String) : BTerm()
+data class BVariable(val name: String, val defaultValue: Boolean?) : BTerm() {
+  constructor(name: String): this(name, true)
+}
 
 /**
  * A term that comes from @defer directives and that needs to be matched against label and current JSON path
diff --git a/libraries/apollo-api/src/commonMain/kotlin/com/apollographql/apollo3/api/CompiledGraphQL.kt b/libraries/apollo-api/src/commonMain/kotlin/com/apollographql/apollo3/api/CompiledGraphQL.kt
index 66dee345c8..1d73362134 100644
--- a/libraries/apollo-api/src/commonMain/kotlin/com/apollographql/apollo3/api/CompiledGraphQL.kt
+++ b/libraries/apollo-api/src/commonMain/kotlin/com/apollographql/apollo3/api/CompiledGraphQL.kt
@@ -132,8 +132,9 @@ class CompiledFragment internal constructor(
   }
 }
 
-
-data class CompiledCondition(val name: String, val inverted: Boolean)
+data class CompiledCondition(val name: String, val inverted: Boolean, val defaultValue: Boolean) {
+  constructor(name: String, inverted: Boolean): this(name, inverted, true)
+}
 
 sealed class CompiledType {
   @Deprecated("Use rawType instead", ReplaceWith("rawType()"))
diff --git a/libraries/apollo-ast/api/apollo-ast.api b/libraries/apollo-ast/api/apollo-ast.api
index 4b297bb52a..bb4727510f 100644
--- a/libraries/apollo-ast/api/apollo-ast.api
+++ b/libraries/apollo-ast/api/apollo-ast.api
@@ -1248,15 +1248,21 @@ public final class com/apollographql/apollo3/ast/introspection/IntrospectionSche
 
 public final class com/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema {
 	public static final field Companion Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Companion;
-	public synthetic fun <init> (ILcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$QueryType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$MutationType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$SubscriptionType;Ljava/util/List;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V
+	public synthetic fun <init> (ILcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$QueryType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$MutationType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$SubscriptionType;Ljava/util/List;Ljava/util/List;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V
 	public fun <init> (Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$QueryType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$MutationType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$SubscriptionType;Ljava/util/List;)V
+	public fun <init> (Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$QueryType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$MutationType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$SubscriptionType;Ljava/util/List;Ljava/util/List;)V
+	public synthetic fun <init> (Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$QueryType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$MutationType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$SubscriptionType;Ljava/util/List;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
 	public final fun component1 ()Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$QueryType;
 	public final fun component2 ()Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$MutationType;
 	public final fun component3 ()Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$SubscriptionType;
 	public final fun component4 ()Ljava/util/List;
-	public final fun copy (Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$QueryType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$MutationType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$SubscriptionType;Ljava/util/List;)Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema;
+	public final fun component5 ()Ljava/util/List;
+	public final synthetic fun copy (Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$QueryType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$MutationType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$SubscriptionType;Ljava/util/List;)Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema;
+	public final fun copy (Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$QueryType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$MutationType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$SubscriptionType;Ljava/util/List;Ljava/util/List;)Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema;
 	public static synthetic fun copy$default (Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$QueryType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$MutationType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$SubscriptionType;Ljava/util/List;ILjava/lang/Object;)Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema;
+	public static synthetic fun copy$default (Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$QueryType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$MutationType;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$SubscriptionType;Ljava/util/List;Ljava/util/List;ILjava/lang/Object;)Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema;
 	public fun equals (Ljava/lang/Object;)Z
+	public final fun getDirectives ()Ljava/util/List;
 	public final fun getMutationType ()Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$MutationType;
 	public final fun getQueryType ()Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$QueryType;
 	public final fun getSubscriptionType ()Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$SubscriptionType;
@@ -1281,6 +1287,108 @@ public final class com/apollographql/apollo3/ast/introspection/IntrospectionSche
 	public final fun serializer ()Lkotlinx/serialization/KSerializer;
 }
 
+public final class com/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive {
+	public static final field Companion Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$Companion;
+	public synthetic fun <init> (ILjava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;ZLkotlinx/serialization/internal/SerializationConstructorMarker;)V
+	public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Z)V
+	public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
+	public final fun component1 ()Ljava/lang/String;
+	public final fun component2 ()Ljava/lang/String;
+	public final fun component3 ()Ljava/util/List;
+	public final fun component4 ()Ljava/util/List;
+	public final fun component5 ()Z
+	public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Z)Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive;
+	public static synthetic fun copy$default (Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;ZILjava/lang/Object;)Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive;
+	public fun equals (Ljava/lang/Object;)Z
+	public final fun getArgs ()Ljava/util/List;
+	public final fun getDescription ()Ljava/lang/String;
+	public final fun getLocations ()Ljava/util/List;
+	public final fun getName ()Ljava/lang/String;
+	public fun hashCode ()I
+	public final fun isRepeatable ()Z
+	public fun toString ()Ljava/lang/String;
+	public static final synthetic fun write$Self (Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V
+}
+
+public final class com/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
+	public static final field INSTANCE Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$$serializer;
+	public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
+	public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive;
+	public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
+	public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
+	public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive;)V
+	public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
+	public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
+}
+
+public final class com/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$Argument {
+	public static final field Companion Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$Argument$Companion;
+	public synthetic fun <init> (ILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$TypeRef;Ljava/lang/String;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V
+	public fun <init> (Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$TypeRef;Ljava/lang/String;)V
+	public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$TypeRef;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+	public final fun component1 ()Ljava/lang/String;
+	public final fun component2 ()Ljava/lang/String;
+	public final fun component3 ()Z
+	public final fun component4 ()Ljava/lang/String;
+	public final fun component5 ()Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$TypeRef;
+	public final fun component6 ()Ljava/lang/String;
+	public final fun copy (Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$TypeRef;Ljava/lang/String;)Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$Argument;
+	public static synthetic fun copy$default (Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$Argument;Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$TypeRef;Ljava/lang/String;ILjava/lang/Object;)Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$Argument;
+	public fun equals (Ljava/lang/Object;)Z
+	public final fun getDefaultValue ()Ljava/lang/String;
+	public final fun getDeprecationReason ()Ljava/lang/String;
+	public final fun getDescription ()Ljava/lang/String;
+	public final fun getName ()Ljava/lang/String;
+	public final fun getType ()Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$TypeRef;
+	public fun hashCode ()I
+	public final fun isDeprecated ()Z
+	public fun toString ()Ljava/lang/String;
+	public static final synthetic fun write$Self (Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$Argument;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V
+}
+
+public final class com/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$Argument$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
+	public static final field INSTANCE Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$Argument$$serializer;
+	public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
+	public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$Argument;
+	public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
+	public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
+	public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$Argument;)V
+	public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
+	public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
+}
+
+public final class com/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$Argument$Companion {
+	public final fun serializer ()Lkotlinx/serialization/KSerializer;
+}
+
+public final class com/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$Companion {
+	public final fun serializer ()Lkotlinx/serialization/KSerializer;
+}
+
+public final class com/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation : java/lang/Enum {
+	public static final field ARGUMENT_DEFINITION Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field ENUM Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field ENUM_VALUE Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field FIELD Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field FIELD_DEFINITION Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field FRAGMENT_DEFINITION Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field FRAGMENT_SPREAD Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field INLINE_FRAGMENT Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field INPUT_FIELD_DEFINITION Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field INPUT_OBJECT Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field INTERFACE Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field MUTATION Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field OBJECT Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field QUERY Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field SCALAR Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field SCHEMA Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field SUBSCRIPTION Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field UNION Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static final field VARIABLE_DEFINITION Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static fun valueOf (Ljava/lang/String;)Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+	public static fun values ()[Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Directive$DirectiveLocation;
+}
+
 public final class com/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Field {
 	public static final field Companion Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$Field$Companion;
 	public synthetic fun <init> (ILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Lcom/apollographql/apollo3/ast/introspection/IntrospectionSchema$Schema$TypeRef;Ljava/util/List;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V
diff --git a/libraries/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/introspection/IntrospectionSchema.kt b/libraries/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/introspection/IntrospectionSchema.kt
index a051abeb54..f14bb4afef 100644
--- a/libraries/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/introspection/IntrospectionSchema.kt
+++ b/libraries/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/introspection/IntrospectionSchema.kt
@@ -28,7 +28,21 @@ data class IntrospectionSchema(
       val mutationType: MutationType?,
       val subscriptionType: SubscriptionType?,
       val types: List<Type>,
+      val directives: List<Directive> = emptyList(),
   ) {
+    constructor(
+        queryType: QueryType,
+        mutationType: MutationType?,
+        subscriptionType: SubscriptionType?,
+        types: List<Type>,
+    ) : this(
+        queryType = queryType,
+        mutationType = mutationType,
+        subscriptionType = subscriptionType,
+        types = types,
+        directives = emptyList(),
+    )
+
     @Serializable
     data class QueryType(val name: String)
 
@@ -122,7 +136,6 @@ data class IntrospectionSchema(
         val type: TypeRef,
         val args: List<Argument> = emptyList(),
     ) {
-
       @Serializable
       data class Argument(
           val name: String,
@@ -144,9 +157,67 @@ data class IntrospectionSchema(
         val ofType: TypeRef? = null,
     )
 
+    /**
+     * An introspection directive
+     */
+    @Serializable
+    data class Directive(
+        val name: String,
+        val description: String?,
+        val locations: List<DirectiveLocation> = emptyList(),
+        val args: List<Argument>,
+        val isRepeatable: Boolean = false,
+    ) {
+      @Serializable
+      data class Argument(
+          val name: String,
+          val description: String?,
+          val isDeprecated: Boolean = false,
+          val deprecationReason: String?,
+          val type: TypeRef,
+          val defaultValue: String?,
+      )
+
+      enum class DirectiveLocation {
+        QUERY,
+        MUTATION,
+        SUBSCRIPTION,
+        FIELD,
+        FRAGMENT_DEFINITION,
+        FRAGMENT_SPREAD,
+        INLINE_FRAGMENT,
+        VARIABLE_DEFINITION,
+        SCHEMA,
+        SCALAR,
+        OBJECT,
+        FIELD_DEFINITION,
+        ARGUMENT_DEFINITION,
+        INTERFACE,
+        UNION,
+        ENUM,
+        ENUM_VALUE,
+        INPUT_OBJECT,
+        INPUT_FIELD_DEFINITION,
+      }
+    }
+
     enum class Kind {
       ENUM, INTERFACE, OBJECT, INPUT_OBJECT, SCALAR, NON_NULL, LIST, UNION
     }
+
+    @Deprecated("For binary compatibility only.", level = DeprecationLevel.HIDDEN)
+    fun copy(
+        queryType: QueryType = this.queryType,
+        mutationType: MutationType? = this.mutationType,
+        subscriptionType: SubscriptionType? = this.subscriptionType,
+        types: List<Type> = this.types,
+    ) = copy(
+        queryType = queryType,
+        mutationType = mutationType,
+        subscriptionType = subscriptionType,
+        types = types,
+        directives = emptyList(),
+    )
   }
 }
 
@@ -168,7 +239,17 @@ fun BufferedSource.toIntrospectionSchema(origin: String = ""): IntrospectionSche
 
   return try {
     val introspectionSchemaEnvelope = json.decodeFromString(IntrospectionSchemaEnvelope.serializer(), this.readUtf8())
-    introspectionSchemaEnvelope.data ?: introspectionSchemaEnvelope.__schema?.let { IntrospectionSchema(it) }
+    introspectionSchemaEnvelope.data ?: introspectionSchemaEnvelope.__schema?.let { schema ->
+      IntrospectionSchema(IntrospectionSchema.Schema(
+          queryType = schema.queryType,
+          mutationType = schema.mutationType,
+          subscriptionType = schema.subscriptionType,
+          types = schema.types,
+          // Old introspection json (pre `April2016`) may not have the `locations` field, in which case the list will be empty, which is invalid. Exclude those directives.
+          // Validation doesn't validate the unknown directives (yet). A future version may want to fail here and enforce proper validation.
+          directives = schema.directives.filter { directive -> directive.locations.isNotEmpty() }
+      ))
+    }
     ?: throw IllegalArgumentException("Invalid introspection schema: $origin")
   } catch (e: Exception) {
     throw RuntimeException("Cannot decode introspection $origin", e)
diff --git a/libraries/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/introspection/introspection_to_schema.kt b/libraries/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/introspection/introspection_to_schema.kt
index 0566b3bbe1..4b9000fafa 100644
--- a/libraries/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/introspection/introspection_to_schema.kt
+++ b/libraries/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/introspection/introspection_to_schema.kt
@@ -6,6 +6,8 @@ import com.apollographql.apollo3.ast.GQLArgument
 import com.apollographql.apollo3.ast.GQLArguments
 import com.apollographql.apollo3.ast.GQLBooleanValue
 import com.apollographql.apollo3.ast.GQLDirective
+import com.apollographql.apollo3.ast.GQLDirectiveDefinition
+import com.apollographql.apollo3.ast.GQLDirectiveLocation
 import com.apollographql.apollo3.ast.GQLDocument
 import com.apollographql.apollo3.ast.GQLEnumTypeDefinition
 import com.apollographql.apollo3.ast.GQLEnumValueDefinition
@@ -34,7 +36,6 @@ import com.apollographql.apollo3.ast.SourceLocation
 import com.apollographql.apollo3.ast.parseAsGQLDocument
 import com.apollographql.apollo3.ast.parseAsGQLValue
 import com.apollographql.apollo3.ast.validateAsSchema
-import com.apollographql.apollo3.ast.withoutBuiltinDefinitions
 import okio.Buffer
 import okio.buffer
 import okio.source
@@ -59,7 +60,9 @@ private class GQLDocumentBuilder(private val introspectionSchema: IntrospectionS
               is IntrospectionSchema.Schema.Type.InputObject -> it.toGQLInputObjectTypeDefinition()
               is IntrospectionSchema.Schema.Type.Scalar -> it.toGQLScalarTypeDefinition()
             }
-          } + schemaDefinition(),
+          }
+              + directives.map { it.toGQLDirectiveDefinition() }
+              + schemaDefinition(),
           filePath = sourceLocation.filePath
       )
     }
@@ -162,6 +165,7 @@ private class GQLDocumentBuilder(private val introspectionSchema: IntrospectionS
       this is Map<*, *> -> GQLObjectValue(fields = this.map {
         GQLObjectField(name = it.key as String, value = it.value.toGQLValue()!!)
       })
+
       this is List<*> -> GQLListValue(values = map { it.toGQLValue()!! })
       else -> throw ConversionException("cannot convert $this to a GQLValue")
     }
@@ -200,9 +204,11 @@ private class GQLDocumentBuilder(private val introspectionSchema: IntrospectionS
       IntrospectionSchema.Schema.Kind.NON_NULL -> GQLNonNullType(
           type = ofType?.toGQLType() ?: throw ConversionException("ofType must not be null for non null types")
       )
+
       IntrospectionSchema.Schema.Kind.LIST -> GQLListType(
           type = ofType?.toGQLType() ?: throw ConversionException("ofType must not be null for list types")
       )
+
       else -> GQLNamedType(
           name = name!!
       )
@@ -274,6 +280,50 @@ private class GQLDocumentBuilder(private val introspectionSchema: IntrospectionS
         directives = emptyList()
     )
   }
+
+  private fun IntrospectionSchema.Schema.Directive.toGQLDirectiveDefinition(): GQLDirectiveDefinition {
+    return GQLDirectiveDefinition(
+        sourceLocation = sourceLocation,
+        description = description,
+        name = name,
+        arguments = args.map { it.toGQLInputValueDefinition() },
+        locations = locations.map { it.toGQLDirectiveLocations() },
+        repeatable = isRepeatable,
+    )
+  }
+
+  private fun IntrospectionSchema.Schema.Directive.Argument.toGQLInputValueDefinition(): GQLInputValueDefinition {
+    return GQLInputValueDefinition(
+        sourceLocation = sourceLocation,
+        name = name,
+        description = description,
+        directives = makeDirectives(deprecationReason),
+        defaultValue = defaultValue.toGQLValue(),
+        type = type.toGQLType(),
+    )
+  }
+
+  private fun IntrospectionSchema.Schema.Directive.DirectiveLocation.toGQLDirectiveLocations() = when (this) {
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.QUERY -> GQLDirectiveLocation.QUERY
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.MUTATION -> GQLDirectiveLocation.MUTATION
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.SUBSCRIPTION -> GQLDirectiveLocation.SUBSCRIPTION
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.FIELD -> GQLDirectiveLocation.FIELD
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.FRAGMENT_DEFINITION -> GQLDirectiveLocation.FRAGMENT_DEFINITION
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.FRAGMENT_SPREAD -> GQLDirectiveLocation.FRAGMENT_SPREAD
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.INLINE_FRAGMENT -> GQLDirectiveLocation.INLINE_FRAGMENT
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.VARIABLE_DEFINITION -> GQLDirectiveLocation.VARIABLE_DEFINITION
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.SCHEMA -> GQLDirectiveLocation.SCHEMA
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.SCALAR -> GQLDirectiveLocation.SCALAR
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.OBJECT -> GQLDirectiveLocation.OBJECT
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.FIELD_DEFINITION -> GQLDirectiveLocation.FIELD_DEFINITION
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.ARGUMENT_DEFINITION -> GQLDirectiveLocation.ARGUMENT_DEFINITION
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.INTERFACE -> GQLDirectiveLocation.INTERFACE
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.UNION -> GQLDirectiveLocation.UNION
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.ENUM -> GQLDirectiveLocation.ENUM
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.ENUM_VALUE -> GQLDirectiveLocation.ENUM_VALUE
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.INPUT_OBJECT -> GQLDirectiveLocation.INPUT_OBJECT
+    IntrospectionSchema.Schema.Directive.DirectiveLocation.INPUT_FIELD_DEFINITION -> GQLDirectiveLocation.INPUT_FIELD_DEFINITION
+  }
 }
 
 /**
@@ -286,10 +336,6 @@ private class GQLDocumentBuilder(private val introspectionSchema: IntrospectionS
 @ApolloExperimental
 fun IntrospectionSchema.toGQLDocument(filePath: String? = null): GQLDocument = GQLDocumentBuilder(this, filePath)
     .toGQLDocument()
-    /**
-     * Introspection already contains builtin types like Int, Boolean, __Schema, etc...
-     */
-    .withoutBuiltinDefinitions()
 
 /**
  * Transforms the [IntrospectionSchema] into a [Schema] that contains builtin definitions
diff --git a/libraries/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/introspection/schema_to_introspection.kt b/libraries/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/introspection/schema_to_introspection.kt
index 028292c794..31b4719ee0 100644
--- a/libraries/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/introspection/schema_to_introspection.kt
+++ b/libraries/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/introspection/schema_to_introspection.kt
@@ -1,6 +1,8 @@
 package com.apollographql.apollo3.ast.introspection
 
 import com.apollographql.apollo3.ast.GQLBooleanValue
+import com.apollographql.apollo3.ast.GQLDirectiveDefinition
+import com.apollographql.apollo3.ast.GQLDirectiveLocation
 import com.apollographql.apollo3.ast.GQLEnumTypeDefinition
 import com.apollographql.apollo3.ast.GQLEnumValue
 import com.apollographql.apollo3.ast.GQLEnumValueDefinition
@@ -46,7 +48,8 @@ private class IntrospectionSchemaBuilder(private val schema: Schema) {
                 is GQLEnumTypeDefinition -> it.toSchemaType()
                 is GQLUnionTypeDefinition -> it.toSchemaType()
               }
-            }
+            },
+            directives = schema.directiveDefinitions.values.map { it.toSchemaDirective() },
         )
     )
   }
@@ -68,11 +71,11 @@ private class IntrospectionSchemaBuilder(private val schema: Schema) {
         isDeprecated = deprecationReason != null,
         deprecationReason = deprecationReason,
         type = type.toSchemaType(schema),
-        args = arguments.map { it.toSchemaArgument() }
+        args = arguments.map { it.toSchemaFieldArgument() }
     )
   }
 
-  private fun GQLInputValueDefinition.toSchemaArgument(): IntrospectionSchema.Schema.Field.Argument {
+  private fun GQLInputValueDefinition.toSchemaFieldArgument(): IntrospectionSchema.Schema.Field.Argument {
     val deprecationReason = directives.findDeprecationReason()
 
     return IntrospectionSchema.Schema.Field.Argument(
@@ -162,6 +165,49 @@ private class IntrospectionSchemaBuilder(private val schema: Schema) {
         possibleTypes = memberTypes.map { it.toSchemaType(schema) }
     )
   }
+
+  private fun GQLInputValueDefinition.toSchemaDirectiveArgument(): IntrospectionSchema.Schema.Directive.Argument {
+    val deprecationReason = directives.findDeprecationReason()
+
+    return IntrospectionSchema.Schema.Directive.Argument(
+        name = name,
+        description = description,
+        isDeprecated = deprecationReason != null,
+        deprecationReason = deprecationReason,
+        type = type.toSchemaType(schema),
+        defaultValue = defaultValue?.toUtf8(indent = "")
+    )
+  }
+
+  private fun GQLDirectiveDefinition.toSchemaDirective() = IntrospectionSchema.Schema.Directive(
+      name = name,
+      description = description,
+      locations = locations.map { it.toSchemaDirectiveLocation() },
+      args = arguments.map { it.toSchemaDirectiveArgument() },
+      isRepeatable = repeatable,
+  )
+
+  private fun GQLDirectiveLocation.toSchemaDirectiveLocation() = when (this) {
+    GQLDirectiveLocation.QUERY -> IntrospectionSchema.Schema.Directive.DirectiveLocation.QUERY
+    GQLDirectiveLocation.MUTATION -> IntrospectionSchema.Schema.Directive.DirectiveLocation.MUTATION
+    GQLDirectiveLocation.SUBSCRIPTION -> IntrospectionSchema.Schema.Directive.DirectiveLocation.SUBSCRIPTION
+    GQLDirectiveLocation.FIELD -> IntrospectionSchema.Schema.Directive.DirectiveLocation.FIELD
+    GQLDirectiveLocation.FRAGMENT_DEFINITION -> IntrospectionSchema.Schema.Directive.DirectiveLocation.FRAGMENT_DEFINITION
+    GQLDirectiveLocation.FRAGMENT_SPREAD -> IntrospectionSchema.Schema.Directive.DirectiveLocation.FRAGMENT_SPREAD
+    GQLDirectiveLocation.INLINE_FRAGMENT -> IntrospectionSchema.Schema.Directive.DirectiveLocation.INLINE_FRAGMENT
+    GQLDirectiveLocation.VARIABLE_DEFINITION -> IntrospectionSchema.Schema.Directive.DirectiveLocation.VARIABLE_DEFINITION
+    GQLDirectiveLocation.SCHEMA -> IntrospectionSchema.Schema.Directive.DirectiveLocation.SCHEMA
+    GQLDirectiveLocation.SCALAR -> IntrospectionSchema.Schema.Directive.DirectiveLocation.SCALAR
+    GQLDirectiveLocation.OBJECT -> IntrospectionSchema.Schema.Directive.DirectiveLocation.OBJECT
+    GQLDirectiveLocation.FIELD_DEFINITION -> IntrospectionSchema.Schema.Directive.DirectiveLocation.FIELD_DEFINITION
+    GQLDirectiveLocation.ARGUMENT_DEFINITION -> IntrospectionSchema.Schema.Directive.DirectiveLocation.ARGUMENT_DEFINITION
+    GQLDirectiveLocation.INTERFACE -> IntrospectionSchema.Schema.Directive.DirectiveLocation.INTERFACE
+    GQLDirectiveLocation.UNION -> IntrospectionSchema.Schema.Directive.DirectiveLocation.UNION
+    GQLDirectiveLocation.ENUM -> IntrospectionSchema.Schema.Directive.DirectiveLocation.ENUM
+    GQLDirectiveLocation.ENUM_VALUE -> IntrospectionSchema.Schema.Directive.DirectiveLocation.ENUM_VALUE
+    GQLDirectiveLocation.INPUT_OBJECT -> IntrospectionSchema.Schema.Directive.DirectiveLocation.INPUT_OBJECT
+    GQLDirectiveLocation.INPUT_FIELD_DEFINITION -> IntrospectionSchema.Schema.Directive.DirectiveLocation.INPUT_FIELD_DEFINITION
+  }
 }
 
 internal fun GQLType.toSchemaType(schema: Schema): IntrospectionSchema.Schema.TypeRef {
@@ -173,12 +219,14 @@ internal fun GQLType.toSchemaType(schema: Schema): IntrospectionSchema.Schema.Ty
           ofType = type.toSchemaType(schema)
       )
     }
+
     is GQLListType -> {
       IntrospectionSchema.Schema.TypeRef(
           kind = IntrospectionSchema.Schema.Kind.LIST,
           name = "", // why "" and not null ?
           ofType = type.toSchemaType(schema))
     }
+
     is GQLNamedType -> {
       IntrospectionSchema.Schema.TypeRef(
           kind = schema.typeDefinition(name).schemaKind(),
diff --git a/libraries/apollo-ast/src/main/resources/builtins.graphqls b/libraries/apollo-ast/src/main/resources/builtins.graphqls
index 7d93a0d703..6af8ac8676 100644
--- a/libraries/apollo-ast/src/main/resources/builtins.graphqls
+++ b/libraries/apollo-ast/src/main/resources/builtins.graphqls
@@ -1,6 +1,10 @@
 # Built in scalar and introspection types from:
 # - https://spec.graphql.org/June2018/#sec-Scalars
-# - https://spec.graphql.org/June2018/#sec-Schema-Introspection
+# - https://github.com/graphql/graphql-spec/blob/afc0a35d271ba9502c3c68aeda6e6c6fbc223774/spec/Section%204%20--%20Introspection.md
+# In theory the user needs to provide the builtin definitions because we cannot know in advance what
+# version of the spec they are using neither if they have extended any of the introspection types.
+# This file is a fallback to make a best-effort guess in case the user didn't provide these definitions, at the
+# risk of potentially validating invalid queries.
 
 """
 The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
@@ -41,30 +45,37 @@ type __Type {
   kind: __TypeKind!
   name: String
   description: String
-
-  # should be non-null for OBJECT and INTERFACE only, must be null for the others
+  # must be non-null for OBJECT and INTERFACE, otherwise null.
   fields(includeDeprecated: Boolean = false): [__Field!]
-
-  # should be non-null for OBJECT and INTERFACE only, must be null for the others
+  # must be non-null for OBJECT and INTERFACE, otherwise null.
   interfaces: [__Type!]
-
-  # should be non-null for INTERFACE and UNION only, always null for the others
+  # must be non-null for INTERFACE and UNION, otherwise null.
   possibleTypes: [__Type!]
-
-  # should be non-null for ENUM only, must be null for the others
+  # must be non-null for ENUM, otherwise null.
   enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
-
-  # should be non-null for INPUT_OBJECT only, must be null for the others
-  inputFields: [__InputValue!]
-
-  # should be non-null for NON_NULL and LIST only, must be null for the others
+  # must be non-null for INPUT_OBJECT, otherwise null.
+  inputFields(includeDeprecated: Boolean = false): [__InputValue!]
+  # must be non-null for NON_NULL and LIST, otherwise null.
   ofType: __Type
+  # may be non-null for custom SCALAR, otherwise null.
+  specifiedByURL: String
+}
+
+enum __TypeKind {
+  SCALAR
+  OBJECT
+  INTERFACE
+  UNION
+  ENUM
+  INPUT_OBJECT
+  LIST
+  NON_NULL
 }
 
 type __Field {
   name: String!
   description: String
-  args: [__InputValue!]!
+  args(includeDeprecated: Boolean = false): [__InputValue!]!
   type: __Type!
   isDeprecated: Boolean!
   deprecationReason: String
@@ -75,6 +86,8 @@ type __InputValue {
   description: String
   type: __Type!
   defaultValue: String
+  isDeprecated: Boolean!
+  deprecationReason: String
 }
 
 type __EnumValue {
@@ -84,22 +97,11 @@ type __EnumValue {
   deprecationReason: String
 }
 
-enum __TypeKind {
-  SCALAR
-  OBJECT
-  INTERFACE
-  UNION
-  ENUM
-  INPUT_OBJECT
-  LIST
-  NON_NULL
-}
-
 type __Directive {
   name: String!
   description: String
   locations: [__DirectiveLocation!]!
-  args: [__InputValue!]!
+  args(includeDeprecated: Boolean = false): [__InputValue!]!
   isRepeatable: Boolean!
 }
 
@@ -137,3 +139,5 @@ directive @defer(
   label: String
   if: Boolean! = true
 ) on FRAGMENT_SPREAD | INLINE_FRAGMENT
+
+directive @specifiedBy(url: String!) on SCALAR
diff --git a/libraries/apollo-cli/src/main/kotlin/com/apollographql/apollo3/cli/DownloadSchemaCommand.kt b/libraries/apollo-cli/src/main/kotlin/com/apollographql/apollo3/cli/DownloadSchemaCommand.kt
index 6ba19e999b..5387e8924e 100644
--- a/libraries/apollo-cli/src/main/kotlin/com/apollographql/apollo3/cli/DownloadSchemaCommand.kt
+++ b/libraries/apollo-cli/src/main/kotlin/com/apollographql/apollo3/cli/DownloadSchemaCommand.kt
@@ -39,7 +39,7 @@ internal class DownloadSchemaCommand: CliktCommand() {
         registryUrl = registryUrl,
         schema = File(schema),
         headers = headersMap,
-        insecure =insecure,
+        insecure = insecure,
     )
   }
-}
\ No newline at end of file
+}
diff --git a/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/kotlin/selections/CompiledSelectionsBuilder.kt b/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/kotlin/selections/CompiledSelectionsBuilder.kt
index 3e11d4b60c..9966248009 100644
--- a/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/kotlin/selections/CompiledSelectionsBuilder.kt
+++ b/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/kotlin/selections/CompiledSelectionsBuilder.kt
@@ -119,7 +119,11 @@ internal class CompiledSelectionsBuilder(
 
     check(expression is BooleanExpression.Element)
 
-    return CodeBlock.of("%T(%S,·%L)", KotlinSymbols.CompiledCondition, expression.value.name, inverted.toString())
+    return if (expression.value.defaultValue != null) {
+      CodeBlock.of("%T(%S,·%L,·%L)", KotlinSymbols.CompiledCondition, expression.value.name, inverted.toString(), expression.value.defaultValue.toString())
+    } else {
+      CodeBlock.of("%T(%S,·%L)", KotlinSymbols.CompiledCondition, expression.value.name, inverted.toString())
+    }
   }
 
   private fun IrArgument.codeBlock(): CodeBlock {
diff --git a/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ir/IrOperationsBuilder.kt b/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ir/IrOperationsBuilder.kt
index d2dfa7dbd3..933ac5c054 100644
--- a/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ir/IrOperationsBuilder.kt
+++ b/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ir/IrOperationsBuilder.kt
@@ -351,7 +351,7 @@ internal class IrOperationsBuilder(
         operationType = operationType.toIrOperationType(schema.rootTypeNameFor(operationType)),
         typeCondition = typeDefinition.name,
         variables = variableDefinitions.map { it.toIr() },
-        selectionSets = SelectionSetsBuilder(schema, allFragmentDefinitions).build(selectionSet.selections, typeDefinition.name),
+        selectionSets = SelectionSetsBuilder(schema, allFragmentDefinitions).build(selectionSet.selections, typeDefinition.name, variableDefinitions),
         sourceWithFragments = sourceWithFragments,
         filePath = sourceLocation.filePath!!,
         dataProperty = dataProperty,
@@ -388,7 +388,7 @@ internal class IrOperationsBuilder(
         filePath = sourceLocation.filePath!!,
         typeCondition = typeDefinition.name,
         variables = inferredVariables.map { it.toIr() },
-        selectionSets = SelectionSetsBuilder(schema, allFragmentDefinitions).build(selectionSet.selections, typeCondition.name),
+        selectionSets = SelectionSetsBuilder(schema, allFragmentDefinitions).build(selectionSet.selections, typeCondition.name, emptyList()),
         interfaceModelGroup = interfaceModelGroup,
         dataProperty = dataProperty,
         dataModelGroup = dataModelGroup,
@@ -520,10 +520,17 @@ internal class IrOperationsBuilder(
       }
       val forceNonNull = gqlField.directives.findNonnull(schema) || parentTypeDefinition.isFieldNonNull(gqlField.name, schema)
 
+      /**
+       * It's ok to always pass the empty list for variableDefinitions because the parsers do not care about @include and @skip
+       * All they care about is that the model types match what is sent by the server
+       */
+      val variableDefinitions: List<GQLVariableDefinition> = emptyList()
+      val condition = gqlField.directives.toIncludeBooleanExpression(variableDefinitions)
+
       CollectedField(
           name = gqlField.name,
           alias = gqlField.alias,
-          condition = gqlField.directives.toIncludeBooleanExpression(),
+          condition = condition,
           selections = gqlField.selectionSet?.selections ?: emptyList(),
           type = fieldDefinition.type,
           description = fieldDefinition.description,
@@ -648,9 +655,9 @@ internal fun GQLValue.toIrValue(): IrValue {
  * - (!)Variable
  * - (!)Variable & (!)Variable
  */
-internal fun List<GQLDirective>.toIncludeBooleanExpression(): BooleanExpression<BVariable> {
+internal fun List<GQLDirective>.toIncludeBooleanExpression(variableDefinitions: List<GQLVariableDefinition>): BooleanExpression<BVariable> {
   val conditions = mapNotNull {
-    it.toIncludeBooleanExpression()
+    it.toIncludeBooleanExpression(variableDefinitions)
   }
   return if (conditions.isEmpty()) {
     BooleanExpression.True
@@ -665,7 +672,7 @@ internal fun List<GQLDirective>.toIncludeBooleanExpression(): BooleanExpression<
   }
 }
 
-internal fun GQLDirective.toIncludeBooleanExpression(): BooleanExpression<BVariable>? {
+internal fun GQLDirective.toIncludeBooleanExpression(variableDefinitions: List<GQLVariableDefinition>): BooleanExpression<BVariable>? {
   if (setOf("skip", "include").contains(name).not()) {
     // not a condition directive
     return null
@@ -681,7 +688,10 @@ internal fun GQLDirective.toIncludeBooleanExpression(): BooleanExpression<BVaria
       if (value.value) BooleanExpression.True else BooleanExpression.False
     }
 
-    is GQLVariableValue -> BooleanExpression.Element(BVariable(name = value.name))
+    is GQLVariableValue -> {
+      val defaultValue = (variableDefinitions.firstOrNull { it.name == value.name }?.defaultValue as? GQLBooleanValue?)?.value
+      BooleanExpression.Element(BVariable(name = value.name, defaultValue = defaultValue))
+    }
     else -> throw IllegalStateException("Apollo: cannot pass ${value.toUtf8()} to '$name' directive")
   }.let {
     if (name == "skip") not(it) else it
@@ -703,7 +713,7 @@ internal fun List<GQLDirective>.toBooleanExpression(): BooleanExpression<BTerm>
     }
     deferBooleanConditions.first()
   }
-  return toIncludeBooleanExpression().and(deferBooleanExpression).simplify()
+  return toIncludeBooleanExpression(emptyList()).and(deferBooleanExpression).simplify()
 }
 
 internal fun GQLDirective.toDeferBooleanExpression(): BooleanExpression<BTerm>? {
diff --git a/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ir/IrSchemaBuilder.kt b/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ir/IrSchemaBuilder.kt
index ea048b25ac..70bab7757b 100644
--- a/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ir/IrSchemaBuilder.kt
+++ b/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ir/IrSchemaBuilder.kt
@@ -38,7 +38,7 @@ object IrSchemaBuilder {
       val typeDefinition = schema.typeDefinition(name)
 
       when {
-        typeDefinition.isBuiltIn() && typeDefinition !is GQLScalarTypeDefinition-> {
+        typeDefinition.isBuiltIn() && typeDefinition !is GQLScalarTypeDefinition && typeDefinition !is GQLEnumTypeDefinition -> {
           // do nothing, introspection types are in apollo-api
         }
         typeDefinition is GQLScalarTypeDefinition -> {
@@ -72,4 +72,4 @@ object IrSchemaBuilder {
         connectionTypes = schema.connectionTypes.toList()
     )
   }
-}
\ No newline at end of file
+}
diff --git a/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ir/SelectionSetsBuilder.kt b/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ir/SelectionSetsBuilder.kt
index 570dcf0813..3963e1f5be 100644
--- a/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ir/SelectionSetsBuilder.kt
+++ b/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ir/SelectionSetsBuilder.kt
@@ -11,6 +11,7 @@ import com.apollographql.apollo3.ast.GQLNamedType
 import com.apollographql.apollo3.ast.GQLNonNullType
 import com.apollographql.apollo3.ast.GQLSelection
 import com.apollographql.apollo3.ast.GQLType
+import com.apollographql.apollo3.ast.GQLVariableDefinition
 import com.apollographql.apollo3.ast.Schema
 import com.apollographql.apollo3.ast.definitionFromScope
 import com.apollographql.apollo3.ast.rawType
@@ -35,8 +36,8 @@ internal class SelectionSetsBuilder(
     return name
   }
 
-  fun build(gqlSelections: List<GQLSelection>, parentType: String): List<IrSelectionSet> {
-    return gqlSelections.walk("root", true, parentType)
+  fun build(gqlSelections: List<GQLSelection>, parentType: String, variableDefinitions: List<GQLVariableDefinition>): List<IrSelectionSet> {
+    return gqlSelections.walk("root", true, parentType, variableDefinitions)
   }
 
   private class WalkResult(val self: IrSelection, val nested: List<IrSelectionSet>)
@@ -44,8 +45,8 @@ internal class SelectionSetsBuilder(
   /**
    * @param name the name to use for this [IrSelectionSet]. Must be unique for a given operation/fragment definition
    */
-  private fun List<GQLSelection>.walk(name: String, isRoot: Boolean, parentType: String): List<IrSelectionSet> {
-    val results = mapNotNull { it.walk(parentType) }
+  private fun List<GQLSelection>.walk(name: String, isRoot: Boolean, parentType: String, variableDefinitions: List<GQLVariableDefinition>): List<IrSelectionSet> {
+    val results = mapNotNull { it.walk(parentType, variableDefinitions) }
 
     /**
      * Order is important. The selection set will ultimately reference nested selection sets, so the nested need to come first
@@ -54,11 +55,11 @@ internal class SelectionSetsBuilder(
     return results.flatMap { it.nested } + IrSelectionSet(name, isRoot, results.map { it.self })
   }
 
-  private fun GQLSelection.walk(parentType: String): WalkResult? {
+  private fun GQLSelection.walk(parentType: String, variableDefinitions: List<GQLVariableDefinition>): WalkResult? {
     return when (this) {
-      is GQLField -> walk(parentType)
-      is GQLInlineFragment -> walk()
-      is GQLFragmentSpread -> walk()
+      is GQLField -> walk(parentType, variableDefinitions)
+      is GQLInlineFragment -> walk(variableDefinitions)
+      is GQLFragmentSpread -> walk(variableDefinitions)
     }
   }
 
@@ -71,8 +72,8 @@ internal class SelectionSetsBuilder(
     )
   }
 
-  private fun GQLField.walk(parentType: String): WalkResult? {
-    val expression = directives.toIncludeBooleanExpression()
+  private fun GQLField.walk(parentType: String, variableDefinitions: List<GQLVariableDefinition>): WalkResult? {
+    val expression = directives.toIncludeBooleanExpression(variableDefinitions)
     if (expression == BooleanExpression.False) {
       return null
     }
@@ -96,7 +97,7 @@ internal class SelectionSetsBuilder(
             condition = expression,
             selectionSetName = if (selectionSet != null) selectionSetName else null
         ),
-        nested = selectionSet?.selections?.walk(selectionSetName, false, fieldDefinition.type.rawType().name).orEmpty()
+        nested = selectionSet?.selections?.walk(selectionSetName, false, fieldDefinition.type.rawType().name, variableDefinitions).orEmpty()
     )
   }
 
@@ -109,8 +110,8 @@ internal class SelectionSetsBuilder(
     is GQLNamedType -> IrNamedTypeRef(name)
   }
 
-  private fun GQLInlineFragment.walk(): WalkResult? {
-    val expression = directives.toIncludeBooleanExpression()
+  private fun GQLInlineFragment.walk(variableDefinitions: List<GQLVariableDefinition>): WalkResult? {
+    val expression = directives.toIncludeBooleanExpression(variableDefinitions)
     if (expression == BooleanExpression.False) {
       return null
     }
@@ -126,12 +127,12 @@ internal class SelectionSetsBuilder(
             selectionSetName = selectionSetName,
             name = null
         ),
-        nested = selectionSet.selections.walk(selectionSetName, false, typeCondition.name)
+        nested = selectionSet.selections.walk(selectionSetName, false, typeCondition.name, variableDefinitions)
     )
   }
 
-  private fun GQLFragmentSpread.walk(): WalkResult? {
-    val expression = directives.toIncludeBooleanExpression()
+  private fun GQLFragmentSpread.walk(variableDefinitions: List<GQLVariableDefinition>): WalkResult? {
+    val expression = directives.toIncludeBooleanExpression(variableDefinitions)
     if (expression == BooleanExpression.False) {
       return null
     }
diff --git a/libraries/apollo-gradle-plugin/build.gradle.kts b/libraries/apollo-gradle-plugin/build.gradle.kts
index a93a58a241..820200e00a 100644
--- a/libraries/apollo-gradle-plugin/build.gradle.kts
+++ b/libraries/apollo-gradle-plugin/build.gradle.kts
@@ -7,6 +7,9 @@ plugins {
 }
 
 apolloLibrary {
+  // See GradleVersionTests.kt the Gradle runner will choke on more recent versions
+  // Keep in sync with TestUtils.kt
+  runTestsWithJavaVersion(11)
 }
 
 // Configuration for extra jar to pass to R8 to give it more context about what can be relocated
diff --git a/libraries/apollo-normalized-cache-api/src/commonMain/kotlin/com/apollographql/apollo3/cache/normalized/api/internal/ShouldSkip.kt b/libraries/apollo-normalized-cache-api/src/commonMain/kotlin/com/apollographql/apollo3/cache/normalized/api/internal/ShouldSkip.kt
index f457b45153..7dfbb30b18 100644
--- a/libraries/apollo-normalized-cache-api/src/commonMain/kotlin/com/apollographql/apollo3/cache/normalized/api/internal/ShouldSkip.kt
+++ b/libraries/apollo-normalized-cache-api/src/commonMain/kotlin/com/apollographql/apollo3/cache/normalized/api/internal/ShouldSkip.kt
@@ -4,7 +4,7 @@ import com.apollographql.apollo3.api.CompiledField
 
 internal fun CompiledField.shouldSkip(variableValues: Map<String, Any?>): Boolean {
   condition.forEach {
-    var value = (variableValues.get(it.name) as? Boolean) ?: false
+    var value = (variableValues.get(it.name) as? Boolean) ?: it.defaultValue
     if (it.inverted) {
       value = !value
     }
diff --git a/libraries/apollo-normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/apollo3/cache/normalized/ClientCacheExtensions.kt b/libraries/apollo-normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/apollo3/cache/normalized/ClientCacheExtensions.kt
index 99b5315b76..f48027594e 100644
--- a/libraries/apollo-normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/apollo3/cache/normalized/ClientCacheExtensions.kt
+++ b/libraries/apollo-normalized-cache-incubating/src/commonMain/kotlin/com/apollographql/apollo3/cache/normalized/ClientCacheExtensions.kt
@@ -31,6 +31,7 @@ import com.apollographql.apollo3.exception.ApolloException
 import com.apollographql.apollo3.exception.CacheMissException
 import com.apollographql.apollo3.interceptor.ApolloInterceptor
 import com.apollographql.apollo3.interceptor.ApolloInterceptorChain
+import com.apollographql.apollo3.interceptor.AutoPersistedQueryInterceptor
 import com.apollographql.apollo3.mpp.currentTimeMillis
 import com.apollographql.apollo3.network.http.HttpInfo
 import kotlinx.coroutines.flow.Flow
@@ -141,6 +142,9 @@ fun ApolloClient.Builder.logCacheMisses(
 }
 
 fun ApolloClient.Builder.store(store: ApolloStore, writeToCacheAsynchronously: Boolean = false): ApolloClient.Builder {
+  check(interceptors.none { it is AutoPersistedQueryInterceptor }) {
+    "Apollo: the normalized cache must be configured before the auto persisted queries"
+  }
   return addInterceptor(WatcherInterceptor(store))
       .addInterceptor(FetchPolicyRouterInterceptor)
       .addInterceptor(ApolloCacheInterceptor(store))
diff --git a/libraries/apollo-normalized-cache/src/commonMain/kotlin/com/apollographql/apollo3/cache/normalized/ClientCacheExtensions.kt b/libraries/apollo-normalized-cache/src/commonMain/kotlin/com/apollographql/apollo3/cache/normalized/ClientCacheExtensions.kt
index 9591e92399..1e5c68f5b4 100644
--- a/libraries/apollo-normalized-cache/src/commonMain/kotlin/com/apollographql/apollo3/cache/normalized/ClientCacheExtensions.kt
+++ b/libraries/apollo-normalized-cache/src/commonMain/kotlin/com/apollographql/apollo3/cache/normalized/ClientCacheExtensions.kt
@@ -28,6 +28,7 @@ import com.apollographql.apollo3.exception.ApolloException
 import com.apollographql.apollo3.exception.CacheMissException
 import com.apollographql.apollo3.interceptor.ApolloInterceptor
 import com.apollographql.apollo3.interceptor.ApolloInterceptorChain
+import com.apollographql.apollo3.interceptor.AutoPersistedQueryInterceptor
 import com.apollographql.apollo3.mpp.currentTimeMillis
 import com.apollographql.apollo3.network.http.HttpInfo
 import kotlinx.coroutines.flow.Flow
@@ -117,6 +118,9 @@ fun ApolloClient.Builder.logCacheMisses(
 }
 
 fun ApolloClient.Builder.store(store: ApolloStore, writeToCacheAsynchronously: Boolean = false): ApolloClient.Builder {
+  check(interceptors.none { it is AutoPersistedQueryInterceptor }) {
+    "Apollo: the normalized cache must be configured before the auto persisted queries"
+  }
   return addInterceptor(WatcherInterceptor(store))
       .addInterceptor(FetchPolicyRouterInterceptor)
       .addInterceptor(ApolloCacheInterceptor(store))
diff --git a/libraries/apollo-runtime-java/src/main/java/com/apollographql/apollo3/runtime/java/ApolloClient.java b/libraries/apollo-runtime-java/src/main/java/com/apollographql/apollo3/runtime/java/ApolloClient.java
index eea031081c..f0bac86de7 100644
--- a/libraries/apollo-runtime-java/src/main/java/com/apollographql/apollo3/runtime/java/ApolloClient.java
+++ b/libraries/apollo-runtime-java/src/main/java/com/apollographql/apollo3/runtime/java/ApolloClient.java
@@ -171,7 +171,6 @@ public class ApolloClient implements Closeable {
     private WebSocket.Factory webSocketFactory;
     private Executor executor;
     private List<ApolloInterceptor> interceptors = new ArrayList<>();
-    private ApolloInterceptor apqInterceptor;
     private List<HttpInterceptor> httpInterceptors = new ArrayList<>();
     private WsProtocol.Factory wsProtocolFactory;
     private List<HttpHeader> wsHeaders = new ArrayList<>();
@@ -354,38 +353,6 @@ public class ApolloClient implements Closeable {
       return this;
     }
 
-
-    public Builder autoPersistedQueries() {
-      return autoPersistedQueries(HttpMethod.Get, HttpMethod.Post, true);
-    }
-
-    public Builder autoPersistedQueries(
-        HttpMethod httpMethodForHashedQueries
-    ) {
-      return autoPersistedQueries(httpMethodForHashedQueries, HttpMethod.Post, true);
-    }
-
-    public Builder autoPersistedQueries(
-        HttpMethod httpMethodForHashedQueries,
-        HttpMethod httpMethodForDocumentQueries
-    ) {
-      return autoPersistedQueries(httpMethodForHashedQueries, httpMethodForDocumentQueries, true);
-    }
-
-    public Builder autoPersistedQueries(
-        HttpMethod httpMethodForHashedQueries,
-        HttpMethod httpMethodForDocumentQueries,
-        boolean enableByDefault
-    ) {
-      apqInterceptor = new AutoPersistedQueryInterceptor(
-              httpMethodForHashedQueries,
-              httpMethodForDocumentQueries);
-
-      enableAutoPersistedQueries(enableByDefault);
-
-      return this;
-    }
-
     public ApolloClient build() {
       if (executor == null) {
         executor = defaultExecutor();
@@ -463,9 +430,6 @@ public class ApolloClient implements Closeable {
         }
       }
 
-      if (apqInterceptor != null) {
-        interceptors.add(apqInterceptor);
-      }
       return new ApolloClient(
           executor,
           networkTransport,
@@ -481,6 +445,38 @@ public class ApolloClient implements Closeable {
       );
     }
 
+    public Builder autoPersistedQueries() {
+      return autoPersistedQueries(HttpMethod.Get, HttpMethod.Post, true);
+    }
+
+    public Builder autoPersistedQueries(
+        HttpMethod httpMethodForHashedQueries
+    ) {
+      return autoPersistedQueries(httpMethodForHashedQueries, HttpMethod.Post, true);
+    }
+
+    public Builder autoPersistedQueries(
+        HttpMethod httpMethodForHashedQueries,
+        HttpMethod httpMethodForDocumentQueries
+    ) {
+      return autoPersistedQueries(httpMethodForHashedQueries, httpMethodForDocumentQueries, true);
+    }
+
+    public Builder autoPersistedQueries(
+        HttpMethod httpMethodForHashedQueries,
+        HttpMethod httpMethodForDocumentQueries,
+        boolean enableByDefault
+    ) {
+      addInterceptor(
+          new AutoPersistedQueryInterceptor(
+              httpMethodForHashedQueries,
+              httpMethodForDocumentQueries
+          )
+      );
+      enableAutoPersistedQueries(enableByDefault);
+
+      return this;
+    }
 
     /**
      * Batch HTTP queries to execute multiple at once. This reduces the number of HTTP round trips at the price of increased latency as
diff --git a/libraries/apollo-runtime/api/apollo-runtime.api b/libraries/apollo-runtime/api/apollo-runtime.api
index b41aee744b..05eca677ac 100644
--- a/libraries/apollo-runtime/api/apollo-runtime.api
+++ b/libraries/apollo-runtime/api/apollo-runtime.api
@@ -168,6 +168,17 @@ public abstract interface class com/apollographql/apollo3/interceptor/ApolloInte
 	public abstract fun proceed (Lcom/apollographql/apollo3/api/ApolloRequest;)Lkotlinx/coroutines/flow/Flow;
 }
 
+public final class com/apollographql/apollo3/interceptor/AutoPersistedQueryInterceptor : com/apollographql/apollo3/interceptor/ApolloInterceptor {
+	public static final field Companion Lcom/apollographql/apollo3/interceptor/AutoPersistedQueryInterceptor$Companion;
+	public static final field PROTOCOL_NEGOTIATION_ERROR_NOT_SUPPORTED Ljava/lang/String;
+	public static final field PROTOCOL_NEGOTIATION_ERROR_QUERY_NOT_FOUND Ljava/lang/String;
+	public fun <init> (Lcom/apollographql/apollo3/api/http/HttpMethod;Lcom/apollographql/apollo3/api/http/HttpMethod;)V
+	public fun intercept (Lcom/apollographql/apollo3/api/ApolloRequest;Lcom/apollographql/apollo3/interceptor/ApolloInterceptorChain;)Lkotlinx/coroutines/flow/Flow;
+}
+
+public final class com/apollographql/apollo3/interceptor/AutoPersistedQueryInterceptor$Companion {
+}
+
 public abstract interface class com/apollographql/apollo3/network/NetworkTransport {
 	public abstract fun dispose ()V
 	public abstract fun execute (Lcom/apollographql/apollo3/api/ApolloRequest;)Lkotlinx/coroutines/flow/Flow;
diff --git a/libraries/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/ApolloClient.kt b/libraries/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/ApolloClient.kt
index 0ab3747333..b093c458b5 100644
--- a/libraries/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/ApolloClient.kt
+++ b/libraries/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/ApolloClient.kt
@@ -171,12 +171,6 @@ private constructor(
     private var subscriptionNetworkTransport: NetworkTransport? = null
     private val customScalarAdaptersBuilder = CustomScalarAdapters.Builder()
     private val _interceptors: MutableList<ApolloInterceptor> = mutableListOf()
-
-    /**
-     * The APQ interceptor is special because it needs to be always last.
-     * If not, there is the risk that it retries cache queries which make no sense.
-     */
-    private var apqInterceptor: ApolloInterceptor? = null
     val interceptors: List<ApolloInterceptor> = _interceptors
     private val httpInterceptors: MutableList<HttpInterceptor> = mutableListOf()
     private var dispatcher: CoroutineDispatcher? = null
@@ -429,11 +423,12 @@ private constructor(
         httpMethodForDocumentQueries: HttpMethod = HttpMethod.Post,
         enableByDefault: Boolean = true,
     ) = apply {
-      apqInterceptor = AutoPersistedQueryInterceptor(
-          httpMethodForHashedQueries,
-          httpMethodForDocumentQueries
+      addInterceptor(
+          AutoPersistedQueryInterceptor(
+              httpMethodForHashedQueries,
+              httpMethodForDocumentQueries
+          )
       )
-
       enableAutoPersistedQueries(enableByDefault)
     }
 
@@ -544,7 +539,7 @@ private constructor(
           networkTransport = networkTransport,
           subscriptionNetworkTransport = subscriptionNetworkTransport,
           customScalarAdapters = customScalarAdaptersBuilder.build(),
-          interceptors = _interceptors + listOfNotNull(apqInterceptor),
+          interceptors = _interceptors,
           dispatcher = dispatcher,
           executionContext = executionContext,
           httpMethod = httpMethod,
diff --git a/libraries/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/interceptor/AutoPersistedQueryInterceptor.kt b/libraries/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/interceptor/AutoPersistedQueryInterceptor.kt
index e6256cca54..16e3e51151 100644
--- a/libraries/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/interceptor/AutoPersistedQueryInterceptor.kt
+++ b/libraries/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/interceptor/AutoPersistedQueryInterceptor.kt
@@ -12,7 +12,7 @@ import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.single
 
-internal class AutoPersistedQueryInterceptor(
+class AutoPersistedQueryInterceptor(
     private val httpMethodForHashedQueries: HttpMethod,
     private val httpMethodForDocumentQueries: HttpMethod,
 ) : ApolloInterceptor {
@@ -77,7 +77,7 @@ internal class AutoPersistedQueryInterceptor(
   }
 
   companion object {
-    private const val PROTOCOL_NEGOTIATION_ERROR_QUERY_NOT_FOUND = "PersistedQueryNotFound"
-    private const val PROTOCOL_NEGOTIATION_ERROR_NOT_SUPPORTED = "PersistedQueryNotSupported"
+    const val PROTOCOL_NEGOTIATION_ERROR_QUERY_NOT_FOUND = "PersistedQueryNotFound"
+    const val PROTOCOL_NEGOTIATION_ERROR_NOT_SUPPORTED = "PersistedQueryNotSupported"
   }
 }
diff --git a/libraries/apollo-tooling/src/main/kotlin/com/apollographql/apollo3/tooling/SchemaDownloader.kt b/libraries/apollo-tooling/src/main/kotlin/com/apollographql/apollo3/tooling/SchemaDownloader.kt
index 19890d1f3c..0d6fa493fb 100644
--- a/libraries/apollo-tooling/src/main/kotlin/com/apollographql/apollo3/tooling/SchemaDownloader.kt
+++ b/libraries/apollo-tooling/src/main/kotlin/com/apollographql/apollo3/tooling/SchemaDownloader.kt
@@ -2,12 +2,12 @@ package com.apollographql.apollo3.tooling
 
 import com.apollographql.apollo3.annotations.ApolloExperimental
 import com.apollographql.apollo3.ast.GQLDocument
-import com.apollographql.apollo3.ast.parseAsGQLDocument
-import com.apollographql.apollo3.ast.toUtf8
-import com.apollographql.apollo3.ast.validateAsSchema
 import com.apollographql.apollo3.ast.introspection.IntrospectionSchema
 import com.apollographql.apollo3.ast.introspection.toGQLDocument
 import com.apollographql.apollo3.ast.introspection.toIntrospectionSchema
+import com.apollographql.apollo3.ast.parseAsGQLDocument
+import com.apollographql.apollo3.ast.toUtf8
+import com.apollographql.apollo3.ast.validateAsSchema
 import com.apollographql.apollo3.compiler.fromJson
 import com.apollographql.apollo3.compiler.toJson
 import okio.Buffer
@@ -44,26 +44,37 @@ object SchemaDownloader {
    * @param headers extra HTTP headers to send during introspection.
    */
   fun download(
-      endpoint: String? = null,
-      graph: String? = null,
-      key: String? = null,
-      graphVariant: String = "current",
+      endpoint: String?,
+      graph: String?,
+      key: String?,
+      graphVariant: String,
       registryUrl: String = "https://graphql.api.apollographql.com/api/graphql",
       schema: File,
       insecure: Boolean = false,
-      headers: Map<String, String> = emptyMap()
+      headers: Map<String, String> = emptyMap(),
   ) {
     var introspectionSchemaJson: String? = null
     var introspectionSchema: IntrospectionSchema? = null
     var gqlSchema: GQLDocument? = null
     when {
       endpoint != null -> {
-        introspectionSchemaJson = downloadIntrospection(
-            endpoint = endpoint,
-            headers = headers,
-            insecure = insecure,
-        )
-        introspectionSchema = introspectionSchemaJson.toIntrospectionSchema()
+        introspectionSchemaJson = try {
+          downloadIntrospection(
+              endpoint = endpoint,
+              headers = headers,
+              insecure = insecure,
+              includeDeprecatedInputFieldsAndArguments = true,
+          )
+        } catch (e: Exception) {
+          // Maybe the server doesn't support deprecated input fields / arguments, try without them
+          downloadIntrospection(
+              endpoint = endpoint,
+              headers = headers,
+              insecure = insecure,
+              includeDeprecatedInputFieldsAndArguments = false,
+          )
+        }
+        introspectionSchema = introspectionSchemaJson!!.toIntrospectionSchema()
       }
       else -> {
         check(key != null) {
@@ -106,10 +117,11 @@ object SchemaDownloader {
       endpoint: String,
       headers: Map<String, String>,
       insecure: Boolean,
+      includeDeprecatedInputFieldsAndArguments: Boolean,
   ): String {
 
     val body = mapOf(
-        "query" to introspectionQuery,
+        "query" to getIntrospectionQuery(includeDeprecatedInputFieldsAndArguments),
         "operationName" to "IntrospectionQuery"
     )
     val response = SchemaHelper.executeQuery(body, endpoint, headers, insecure)
@@ -163,72 +175,72 @@ object SchemaDownloader {
 
   inline fun <reified T> Any?.cast() = this as? T
 
-  private val introspectionQuery = """
-    query IntrospectionQuery {
-      __schema {
-        queryType { name }
-        mutationType { name }
-        subscriptionType { name }
-        types {
-          ...FullType
+  private fun getIntrospectionQuery(includeDeprecatedInputFieldsAndArguments: Boolean): String {
+    val includeDeprecated = if (includeDeprecatedInputFieldsAndArguments) "(includeDeprecated: true)" else ""
+    return """
+      query IntrospectionQuery {
+        __schema {
+          queryType { name }
+          mutationType { name }
+          subscriptionType { name }
+          types {
+            ...FullType
+          }
+          directives {
+            name
+            description
+            locations
+            args$includeDeprecated {
+              ...InputValue
+            }
+            isRepeatable
+          }
         }
-        directives {
+      }
+  
+      fragment FullType on __Type {
+        kind
+        name
+        description
+        fields(includeDeprecated: true) {
           name
           description
-          locations
-          args {
+          args$includeDeprecated {
             ...InputValue
           }
+          type {
+            ...TypeRef
+          }
+          isDeprecated
+          deprecationReason
         }
-      }
-    }
-
-    fragment FullType on __Type {
-      kind
-      name
-      description
-      fields(includeDeprecated: true) {
-        name
-        description
-        args {
+        inputFields$includeDeprecated {
           ...InputValue
         }
-        type {
+        interfaces {
+          ...TypeRef
+        }
+        enumValues(includeDeprecated: true) {
+          name
+          description
+          isDeprecated
+          deprecationReason
+        }
+        possibleTypes {
           ...TypeRef
         }
-        isDeprecated
-        deprecationReason
-      }
-      inputFields(includeDeprecated: true) {
-        ...InputValue
-      }
-      interfaces {
-        ...TypeRef
       }
-      enumValues(includeDeprecated: true) {
+  
+      fragment InputValue on __InputValue {
         name
         description
+        type { ...TypeRef }
+        defaultValue
         isDeprecated
         deprecationReason
       }
-      possibleTypes {
-        ...TypeRef
-      }
-    }
-
-    fragment InputValue on __InputValue {
-      name
-      description
-      type { ...TypeRef }
-      defaultValue
-      isDeprecated
-      deprecationReason
-    }
-
-    fragment TypeRef on __Type {
-      kind
-      name
-      ofType {
+  
+      fragment TypeRef on __Type {
         kind
         name
         ofType {
@@ -249,12 +261,16 @@ object SchemaDownloader {
                   ofType {
                     kind
                     name
+                    ofType {
+                      kind
+                      name
+                    }
                   }
                 }
               }
             }
           }
         }
-      }
-    }""".trimIndent()
+      }""".trimIndent()
+  }
 }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 9e3fcbc574..a5c952bd62 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -18,4 +18,8 @@ pluginManagement {
   includeBuild("build-logic")
 }
 
+plugins {
+  id("org.gradle.toolchains.foojay-resolver-convention") version "0.4.0"
+}
+
 apply(from = "./gradle/repositories.gradle.kts")


Test patch:
diff --git a/.github/workflows/defer-with-router-tests.yml b/.github/workflows/defer-with-router-tests.yml
index 221fce976b..486ccc4f69 100644
--- a/.github/workflows/defer-with-router-tests.yml
+++ b/.github/workflows/defer-with-router-tests.yml
@@ -30,7 +30,7 @@ jobs:
         uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b #v3.9.0
         with:
           distribution: 'temurin'
-          java-version: 11
+          java-version: 17
 
       - name: Setup Gradle
         uses: gradle/gradle-build-action@3fbe033aaae657f011f88f29be9e65ed26bd29ef #v2.3.3
diff --git a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/TestOperation.graphql b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/TestOperation.graphql
index 1a2927ce03..1af9873b63 100644
--- a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/TestOperation.graphql
+++ b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/TestOperation.graphql
@@ -9,5 +9,6 @@ query TestQuery {
   }
   __type(name: "Vehicle") {
     name
+    kind
   }
 }
diff --git a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/TestQuery.java.expected b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/TestQuery.java.expected
index 59f19a7541..6966b1dff6 100644
--- a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/TestQuery.java.expected
+++ b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/TestQuery.java.expected
@@ -13,6 +13,7 @@ import com.apollographql.apollo3.api.Query;
 import com.apollographql.apollo3.api.json.JsonWriter;
 import com.example.introspection_query.adapter.TestQuery_ResponseAdapter;
 import com.example.introspection_query.selections.TestQuerySelections;
+import com.example.introspection_query.type.__TypeKind;
 import java.io.IOException;
 import java.lang.Object;
 import java.lang.Override;
@@ -20,7 +21,7 @@ import java.lang.String;
 import java.util.List;
 
 public class TestQuery implements Query<TestQuery.Data> {
-  public static final String OPERATION_ID = "0df748160db73d1bbdea0e6e8437222dd4026ef9a3d699923485cf95c7df8366";
+  public static final String OPERATION_ID = "2bf29cc74f10b0b5551a609396f4e489fc4ebce15c0504cdd102be8447976b97";
 
   /**
    * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -37,10 +38,11 @@ public class TestQuery implements Query<TestQuery.Data> {
    *   }
    *   __type(name: "Vehicle") {
    *     name
+   *     kind
    *   }
    * }
    */
-  public static final String OPERATION_DOCUMENT = "query TestQuery { __schema { queryType { name } types { name } } __type(name: \"Vehicle\") { name } }";
+  public static final String OPERATION_DOCUMENT = "query TestQuery { __schema { queryType { name } types { name } } __type(name: \"Vehicle\") { name kind } }";
 
   public static final String OPERATION_NAME = "TestQuery";
 
@@ -342,14 +344,17 @@ public class TestQuery implements Query<TestQuery.Data> {
   public static class __Type {
     public String name;
 
+    public __TypeKind kind;
+
     private transient volatile int $hashCode;
 
     private transient volatile boolean $hashCodeMemoized;
 
     private transient volatile String $toString;
 
-    public __Type(String name) {
+    public __Type(String name, __TypeKind kind) {
       this.name = name;
+      this.kind = kind;
     }
 
     @Override
@@ -359,7 +364,8 @@ public class TestQuery implements Query<TestQuery.Data> {
       }
       if (o instanceof __Type) {
         __Type that = (__Type) o;
-        return ((this.name == null) ? (that.name == null) : this.name.equals(that.name));
+        return ((this.name == null) ? (that.name == null) : this.name.equals(that.name))
+         &&((this.kind == null) ? (that.kind == null) : this.kind.equals(that.kind));
       }
       return false;
     }
@@ -370,6 +376,8 @@ public class TestQuery implements Query<TestQuery.Data> {
         int h = 1;
         h *= 1000003;
         h ^= (name == null) ? 0 : name.hashCode();
+        h *= 1000003;
+        h ^= (kind == null) ? 0 : kind.hashCode();
         $hashCode = h;
         $hashCodeMemoized = true;
       }
@@ -380,7 +388,8 @@ public class TestQuery implements Query<TestQuery.Data> {
     public String toString() {
       if ($toString == null) {
         $toString = "__Type{"
-          + "name=" + name
+          + "name=" + name + ", "
+          + "kind=" + kind
           + "}";
       }
       return $toString;
diff --git a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/adapter/TestQuery_ResponseAdapter.java.expected b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/adapter/TestQuery_ResponseAdapter.java.expected
index 798b2ed881..0fa29d23f3 100644
--- a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/adapter/TestQuery_ResponseAdapter.java.expected
+++ b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/adapter/TestQuery_ResponseAdapter.java.expected
@@ -14,6 +14,8 @@ import com.apollographql.apollo3.api.ObjectAdapter;
 import com.apollographql.apollo3.api.json.JsonReader;
 import com.apollographql.apollo3.api.json.JsonWriter;
 import com.example.introspection_query.TestQuery;
+import com.example.introspection_query.type.__TypeKind;
+import com.example.introspection_query.type.adapter.__TypeKind_ResponseAdapter;
 import java.io.IOException;
 import java.lang.Override;
 import java.lang.String;
@@ -166,23 +168,28 @@ public class TestQuery_ResponseAdapter {
   public enum __Type implements Adapter<TestQuery.__Type> {
     INSTANCE;
 
-    private static final List<String> RESPONSE_NAMES = Arrays.asList("name");
+    private static final List<String> RESPONSE_NAMES = Arrays.asList("name", "kind");
 
     @Override
     public TestQuery.__Type fromJson(JsonReader reader, CustomScalarAdapters customScalarAdapters)
         throws IOException {
       String _name = null;
+      __TypeKind _kind = null;
 
       loop:
       while(true) {
         switch (reader.selectName(RESPONSE_NAMES)) {
           case 0: _name = Adapters.NullableStringAdapter.fromJson(reader, customScalarAdapters); break;
+          case 1: _kind = __TypeKind_ResponseAdapter.INSTANCE.fromJson(reader, customScalarAdapters); break;
           default: break loop;
         }
       }
 
+      Assertions.checkFieldNotMissing(_kind, "kind");
+
       return new TestQuery.__Type(
-        _name
+        _name,
+        _kind
       );
     }
 
@@ -191,6 +198,9 @@ public class TestQuery_ResponseAdapter {
         TestQuery.__Type value) throws IOException {
       writer.name("name");
       Adapters.NullableStringAdapter.toJson(writer, customScalarAdapters, value.name);
+
+      writer.name("kind");
+      __TypeKind_ResponseAdapter.INSTANCE.toJson(writer, customScalarAdapters, value.kind);
     }
   }
 }
diff --git a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/selections/TestQuerySelections.java.expected b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/selections/TestQuerySelections.java.expected
index 782abe7e69..8ee31f88cb 100644
--- a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/selections/TestQuerySelections.java.expected
+++ b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/selections/TestQuerySelections.java.expected
@@ -12,6 +12,7 @@ import com.apollographql.apollo3.api.CompiledListType;
 import com.apollographql.apollo3.api.CompiledNotNullType;
 import com.apollographql.apollo3.api.CompiledSelection;
 import com.example.introspection_query.type.GraphQLString;
+import com.example.introspection_query.type.__TypeKind;
 import java.util.Arrays;
 import java.util.List;
 
@@ -30,7 +31,8 @@ public class TestQuerySelections {
   );
 
   private static List<CompiledSelection> ____type = Arrays.asList(
-    new CompiledField.Builder("name", GraphQLString.type).build()
+    new CompiledField.Builder("name", GraphQLString.type).build(),
+    new CompiledField.Builder("kind", new CompiledNotNullType(__TypeKind.type)).build()
   );
 
   public static List<CompiledSelection> __root = Arrays.asList(
diff --git a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/type/__TypeKind.java.expected b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/type/__TypeKind.java.expected
new file mode 100644
index 0000000000..006fc86980
--- /dev/null
+++ b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/type/__TypeKind.java.expected
@@ -0,0 +1,97 @@
+//
+// AUTO-GENERATED FILE. DO NOT MODIFY.
+//
+// This class was automatically generated by Apollo GraphQL version '$VERSION'.
+//
+package com.example.introspection_query.type;
+
+import com.apollographql.apollo3.api.EnumType;
+import java.lang.Object;
+import java.lang.Override;
+import java.lang.String;
+import java.util.Arrays;
+
+public class __TypeKind {
+  public static EnumType type = new EnumType("__TypeKind", Arrays.asList("SCALAR", "OBJECT", "INTERFACE", "UNION", "ENUM", "INPUT_OBJECT", "LIST", "NON_NULL"));
+
+  public static __TypeKind SCALAR = new __TypeKind("SCALAR");
+
+  public static __TypeKind OBJECT = new __TypeKind("OBJECT");
+
+  public static __TypeKind INTERFACE = new __TypeKind("INTERFACE");
+
+  public static __TypeKind UNION = new __TypeKind("UNION");
+
+  public static __TypeKind ENUM = new __TypeKind("ENUM");
+
+  public static __TypeKind INPUT_OBJECT = new __TypeKind("INPUT_OBJECT");
+
+  public static __TypeKind LIST = new __TypeKind("LIST");
+
+  public static __TypeKind NON_NULL = new __TypeKind("NON_NULL");
+
+  public String rawValue;
+
+  public __TypeKind(String rawValue) {
+    this.rawValue = rawValue;
+  }
+
+  public static __TypeKind safeValueOf(String rawValue) {
+    switch(rawValue) {
+      case "SCALAR": return __TypeKind.SCALAR;
+      case "OBJECT": return __TypeKind.OBJECT;
+      case "INTERFACE": return __TypeKind.INTERFACE;
+      case "UNION": return __TypeKind.UNION;
+      case "ENUM": return __TypeKind.ENUM;
+      case "INPUT_OBJECT": return __TypeKind.INPUT_OBJECT;
+      case "LIST": return __TypeKind.LIST;
+      case "NON_NULL": return __TypeKind.NON_NULL;
+      default: return new __TypeKind.UNKNOWN__(rawValue);
+    }
+  }
+
+  /**
+   * An enum value that wasn't known at compile time.
+   */
+  public static class UNKNOWN__ extends __TypeKind {
+    private transient volatile int $hashCode;
+
+    private transient volatile boolean $hashCodeMemoized;
+
+    private transient volatile String $toString;
+
+    public UNKNOWN__(String rawValue) {
+      super(rawValue);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (o == this) {
+        return true;
+      }
+      if (o instanceof UNKNOWN__) {
+        return true;
+      }
+      return false;
+    }
+
+    @Override
+    public int hashCode() {
+      if (!$hashCodeMemoized) {
+        int h = 1;
+        $hashCode = h;
+        $hashCodeMemoized = true;
+      }
+      return $hashCode;
+    }
+
+    @Override
+    public String toString() {
+      if ($toString == null) {
+        $toString = "UNKNOWN__{"
+          + "}";
+      }
+      return $toString;
+    }
+  }
+}
diff --git a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/type/adapter/__TypeKind_ResponseAdapter.java.expected b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/type/adapter/__TypeKind_ResponseAdapter.java.expected
new file mode 100644
index 0000000000..ab109cb45a
--- /dev/null
+++ b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/java/operationBased/introspection_query/type/adapter/__TypeKind_ResponseAdapter.java.expected
@@ -0,0 +1,31 @@
+//
+// AUTO-GENERATED FILE. DO NOT MODIFY.
+//
+// This class was automatically generated by Apollo GraphQL version '$VERSION'.
+//
+package com.example.introspection_query.type.adapter;
+
+import com.apollographql.apollo3.api.Adapter;
+import com.apollographql.apollo3.api.CustomScalarAdapters;
+import com.apollographql.apollo3.api.json.JsonReader;
+import com.apollographql.apollo3.api.json.JsonWriter;
+import com.example.introspection_query.type.__TypeKind;
+import java.io.IOException;
+import java.lang.Override;
+
+public enum __TypeKind_ResponseAdapter implements Adapter<__TypeKind> {
+  INSTANCE;
+
+  @Override
+  public __TypeKind fromJson(JsonReader reader, CustomScalarAdapters customScalarAdapters) throws
+      IOException {
+    String rawValue = reader.nextString();
+    return __TypeKind.safeValueOf(rawValue);
+  }
+
+  @Override
+  public void toJson(JsonWriter writer, CustomScalarAdapters customScalarAdapters, __TypeKind value)
+      throws IOException {
+    writer.value(value.rawValue);
+  }
+}
diff --git a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/TestQuery.kt.expected b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/TestQuery.kt.expected
index 999bf9c9ce..fd78c7b9f7 100644
--- a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/TestQuery.kt.expected
+++ b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/TestQuery.kt.expected
@@ -14,6 +14,7 @@ import com.apollographql.apollo3.api.json.JsonWriter
 import com.apollographql.apollo3.api.obj
 import com.example.introspection_query.adapter.TestQuery_ResponseAdapter
 import com.example.introspection_query.selections.TestQuerySelections
+import com.example.introspection_query.type.__TypeKind
 import kotlin.Any
 import kotlin.Boolean
 import kotlin.Int
@@ -66,12 +67,13 @@ public class TestQuery() : Query<TestQuery.Data> {
 
     public data class __Type(
       public val name: String?,
+      public val kind: __TypeKind,
     )
   }
 
   public companion object {
     public const val OPERATION_ID: String =
-        "0df748160db73d1bbdea0e6e8437222dd4026ef9a3d699923485cf95c7df8366"
+        "2bf29cc74f10b0b5551a609396f4e489fc4ebce15c0504cdd102be8447976b97"
 
     /**
      * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -88,12 +90,13 @@ public class TestQuery() : Query<TestQuery.Data> {
      *   }
      *   __type(name: "Vehicle") {
      *     name
+     *     kind
      *   }
      * }
      */
     public val OPERATION_DOCUMENT: String
       get() =
-          "query TestQuery { __schema { queryType { name } types { name } } __type(name: \"Vehicle\") { name } }"
+          "query TestQuery { __schema { queryType { name } types { name } } __type(name: \"Vehicle\") { name kind } }"
 
     public const val OPERATION_NAME: String = "TestQuery"
   }
diff --git a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/adapter/TestQuery_ResponseAdapter.kt.expected b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/adapter/TestQuery_ResponseAdapter.kt.expected
index 3eb26269d1..6ab8cb2d91 100644
--- a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/adapter/TestQuery_ResponseAdapter.kt.expected
+++ b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/adapter/TestQuery_ResponseAdapter.kt.expected
@@ -13,6 +13,8 @@ import com.apollographql.apollo3.api.json.JsonWriter
 import com.apollographql.apollo3.api.list
 import com.apollographql.apollo3.api.obj
 import com.example.introspection_query.TestQuery
+import com.example.introspection_query.type.__TypeKind
+import com.example.introspection_query.type.adapter.__TypeKind_ResponseAdapter
 import kotlin.String
 import kotlin.Unit
 import kotlin.collections.List
@@ -146,21 +148,24 @@ public object TestQuery_ResponseAdapter {
     }
 
     private object __Type : Adapter<TestQuery.Data.__Type> {
-      public val RESPONSE_NAMES: List<String> = listOf("name")
+      public val RESPONSE_NAMES: List<String> = listOf("name", "kind")
 
       public override fun fromJson(reader: JsonReader, customScalarAdapters: CustomScalarAdapters):
           TestQuery.Data.__Type {
         var _name: String? = null
+        var _kind: __TypeKind? = null
 
         while(true) {
           when (reader.selectName(RESPONSE_NAMES)) {
             0 -> _name = NullableStringAdapter.fromJson(reader, customScalarAdapters)
+            1 -> _kind = __TypeKind_ResponseAdapter.fromJson(reader, customScalarAdapters)
             else -> break
           }
         }
 
         return TestQuery.Data.__Type(
-          name = _name
+          name = _name,
+          kind = _kind!!
         )
       }
 
@@ -171,6 +176,9 @@ public object TestQuery_ResponseAdapter {
       ): Unit {
         writer.name("name")
         NullableStringAdapter.toJson(writer, customScalarAdapters, value.name)
+
+        writer.name("kind")
+        __TypeKind_ResponseAdapter.toJson(writer, customScalarAdapters, value.kind)
       }
     }
   }
diff --git a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/selections/TestQuerySelections.kt.expected b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/selections/TestQuerySelections.kt.expected
index b8f103c68a..151af52d11 100644
--- a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/selections/TestQuerySelections.kt.expected
+++ b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/selections/TestQuerySelections.kt.expected
@@ -13,6 +13,7 @@ import com.apollographql.apollo3.api.CompiledTypeType
 import com.apollographql.apollo3.api.list
 import com.apollographql.apollo3.api.notNull
 import com.example.introspection_query.type.GraphQLString
+import com.example.introspection_query.type.__TypeKind
 import kotlin.collections.List
 
 public object TestQuerySelections {
@@ -47,6 +48,10 @@ public object TestQuerySelections {
         CompiledField.Builder(
           name = "name",
           type = GraphQLString.type
+        ).build(),
+        CompiledField.Builder(
+          name = "kind",
+          type = __TypeKind.type.notNull()
         ).build()
       )
 
diff --git a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/type/__TypeKind.kt.expected b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/type/__TypeKind.kt.expected
new file mode 100644
index 0000000000..6f569caba8
--- /dev/null
+++ b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/type/__TypeKind.kt.expected
@@ -0,0 +1,49 @@
+//
+// AUTO-GENERATED FILE. DO NOT MODIFY.
+//
+// This class was automatically generated by Apollo GraphQL version '$VERSION'.
+//
+package com.example.introspection_query.type
+
+import com.apollographql.apollo3.api.EnumType
+import kotlin.Array
+import kotlin.String
+
+public enum class __TypeKind(
+  public val rawValue: String,
+) {
+  SCALAR("SCALAR"),
+  OBJECT("OBJECT"),
+  INTERFACE("INTERFACE"),
+  UNION("UNION"),
+  ENUM("ENUM"),
+  INPUT_OBJECT("INPUT_OBJECT"),
+  LIST("LIST"),
+  NON_NULL("NON_NULL"),
+  /**
+   * Auto generated constant for unknown enum values
+   */
+  UNKNOWN__("UNKNOWN__"),
+  ;
+
+  public companion object {
+    public val type: EnumType = EnumType("__TypeKind", listOf("SCALAR", "OBJECT", "INTERFACE",
+        "UNION", "ENUM", "INPUT_OBJECT", "LIST", "NON_NULL"))
+
+    public fun safeValueOf(rawValue: String): __TypeKind = values().find { it.rawValue == rawValue }
+        ?: UNKNOWN__
+
+    /**
+     * Returns all [__TypeKind] known at compile time
+     */
+    public fun knownValues(): Array<__TypeKind> = arrayOf(
+      SCALAR,
+      OBJECT,
+      INTERFACE,
+      UNION,
+      ENUM,
+      INPUT_OBJECT,
+      LIST,
+      NON_NULL)
+  }
+}
diff --git a/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/type/adapter/__TypeKind_ResponseAdapter.kt.expected b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/type/adapter/__TypeKind_ResponseAdapter.kt.expected
new file mode 100644
index 0000000000..ff34ede016
--- /dev/null
+++ b/libraries/apollo-compiler/src/test/graphql/com/example/introspection_query/kotlin/responseBased/introspection_query/type/adapter/__TypeKind_ResponseAdapter.kt.expected
@@ -0,0 +1,29 @@
+//
+// AUTO-GENERATED FILE. DO NOT MODIFY.
+//
+// This class was automatically generated by Apollo GraphQL version '$VERSION'.
+//
+package com.example.introspection_query.type.adapter
+
+import com.apollographql.apollo3.api.Adapter
+import com.apollographql.apollo3.api.CustomScalarAdapters
+import com.apollographql.apollo3.api.json.JsonReader
+import com.apollographql.apollo3.api.json.JsonWriter
+import com.example.introspection_query.type.__TypeKind
+import kotlin.Unit
+
+public object __TypeKind_ResponseAdapter : Adapter<__TypeKind> {
+  public override fun fromJson(reader: JsonReader, customScalarAdapters: CustomScalarAdapters):
+      __TypeKind {
+    val rawValue = reader.nextString()!!
+    return __TypeKind.safeValueOf(rawValue)
+  }
+
+  public override fun toJson(
+    writer: JsonWriter,
+    customScalarAdapters: CustomScalarAdapters,
+    `value`: __TypeKind,
+  ): Unit {
+    writer.value(value.rawValue)
+  }
+}
diff --git a/libraries/apollo-gradle-plugin/src/test/kotlin/com/apollographql/apollo3/gradle/test/ConvertSchemaTests.kt b/libraries/apollo-gradle-plugin/src/test/kotlin/com/apollographql/apollo3/gradle/test/ConvertSchemaTests.kt
index 074b6911df..fd1d02037a 100644
--- a/libraries/apollo-gradle-plugin/src/test/kotlin/com/apollographql/apollo3/gradle/test/ConvertSchemaTests.kt
+++ b/libraries/apollo-gradle-plugin/src/test/kotlin/com/apollographql/apollo3/gradle/test/ConvertSchemaTests.kt
@@ -3,7 +3,6 @@ package com.apollographql.apollo3.gradle.test
 import com.apollographql.apollo3.ast.introspection.normalize
 import com.apollographql.apollo3.ast.introspection.toIntrospectionSchema
 import com.apollographql.apollo3.gradle.util.TestUtils
-import com.google.common.truth.Truth
 import org.gradle.testkit.runner.TaskOutcome
 import org.junit.Assert
 import org.junit.Test
@@ -74,12 +73,31 @@ class ConvertSchemaTests {
           to.absolutePath
       )
       Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":convertApolloSchema")!!.outcome)
-      // SDL to Json and back is not idempotent as SDL will add a `schema {}` block
-      Truth.assertThat(to.readText()).contains("""
-        type Query {
-          greeting: String
-        }
-      """.trimIndent())
+      assertjThat(to.readText())
+          .isEqualTo(File(dir, "schemas/schema.sdl").readText())
     }
   }
+
+  @Test
+  fun `convert from october-2015 JSON to SDL works`() {
+    TestUtils.withTestProject("convertSchema") { dir ->
+      // schema-october-2015.json doesn't have:
+      // - `__Directive.locations` (introduced in the April2016 spec)
+      // - `__Directive.isRepeatable` (introduced in the October2021 spec)
+      // - `__InputField.isDeprecated` and `__InputField.deprecatedReason` (introduced after the October2021 spec)
+      val from = File(dir, "schemas/schema-october-2015-spec.json")
+      val to = File(dir, "schema.sdl")
+      val result = TestUtils.executeTask("convertApolloSchema",
+          dir,
+          "--from",
+          from.absolutePath,
+          "--to",
+          to.absolutePath
+      )
+      Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":convertApolloSchema")!!.outcome)
+      assertjThat(to.readText())
+          .isEqualTo(File(dir, "schemas/schema-october-2015-spec.sdl").readText())
+    }
+  }
+
 }
diff --git a/libraries/apollo-gradle-plugin/src/test/kotlin/com/apollographql/apollo3/gradle/test/DownloadSchemaTests.kt b/libraries/apollo-gradle-plugin/src/test/kotlin/com/apollographql/apollo3/gradle/test/DownloadSchemaTests.kt
index 653191ee05..aa4c693d6d 100644
--- a/libraries/apollo-gradle-plugin/src/test/kotlin/com/apollographql/apollo3/gradle/test/DownloadSchemaTests.kt
+++ b/libraries/apollo-gradle-plugin/src/test/kotlin/com/apollographql/apollo3/gradle/test/DownloadSchemaTests.kt
@@ -9,6 +9,8 @@ import okhttp3.tls.HandshakeCertificates
 import okhttp3.tls.HeldCertificate
 import org.gradle.testkit.runner.TaskOutcome
 import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
 import org.junit.Test
 import java.io.File
 
@@ -140,6 +142,27 @@ class DownloadSchemaTests {
     }
   }
 
+  @Test
+  fun `schema is downloaded correctly when server doesn't support deprecated input fields and arguments`() {
+    withSimpleProject(apolloConfiguration = apolloConfiguration) { dir ->
+      mockServer.enqueue(MockResponse().setResponseCode(400))
+      mockServer.enqueue(MockResponse().setBody(schemaString1))
+
+      TestUtils.executeTask("downloadMockApolloSchemaFromIntrospection", dir)
+
+      mockServer.takeRequest().body.readUtf8().let {
+        assertTrue(it.contains("inputFields(includeDeprecated: true)"))
+        assertTrue(it.contains("args(includeDeprecated: true)"))
+      }
+      mockServer.takeRequest().body.readUtf8().let {
+        assertFalse(it.contains("inputFields(includeDeprecated: true)"))
+        assertFalse(it.contains("args(includeDeprecated: true)"))
+      }
+      assertEquals(schemaString1, File(dir, "src/main/graphql/com/example/schema.json").readText())
+    }
+  }
+
+
   @Test
   fun `download schema is never up-to-date`() {
 
@@ -231,4 +254,5 @@ class DownloadSchemaTests {
       assertEquals(schemaString1, schema.readText())
     }
   }
+
 }
diff --git a/libraries/apollo-gradle-plugin/src/test/kotlin/com/apollographql/apollo3/gradle/util/TestUtils.kt b/libraries/apollo-gradle-plugin/src/test/kotlin/com/apollographql/apollo3/gradle/util/TestUtils.kt
index 28368cd09b..2e16fb357e 100644
--- a/libraries/apollo-gradle-plugin/src/test/kotlin/com/apollographql/apollo3/gradle/util/TestUtils.kt
+++ b/libraries/apollo-gradle-plugin/src/test/kotlin/com/apollographql/apollo3/gradle/util/TestUtils.kt
@@ -66,14 +66,6 @@ object TestUtils {
       appendLine("}")
       appendLine()
 
-      append("""
-        java {
-          toolchain { 
-            languageVersion.set(JavaLanguageVersion.of(8))
-          }
-        }
-      """.trimIndent())
-
       appendLine()
       append("""
         dependencies {
@@ -92,6 +84,13 @@ object TestUtils {
             |android {
             |  compileSdkVersion(libs.versions.android.sdkversion.compile.get().toInteger())
             |  namespace = "com.example"
+            |  
+            |  // Keep in sync with apollo-gradle-plugin/build.gradle.kts
+            |  // https://issuetracker.google.com/issues/260059413  
+            |  compileOptions {
+            |    sourceCompatibility = 11
+            |    targetCompatibility = 11
+            |  }
             |
           """.trimMargin()
         )
diff --git a/libraries/apollo-gradle-plugin/testProjects/convertSchema/schemas/schema-october-2015-spec.json b/libraries/apollo-gradle-plugin/testProjects/convertSchema/schemas/schema-october-2015-spec.json
new file mode 100644
index 0000000000..b426e95255
--- /dev/null
+++ b/libraries/apollo-gradle-plugin/testProjects/convertSchema/schemas/schema-october-2015-spec.json
@@ -0,0 +1,778 @@
+{
+  "__schema": {
+    "queryType": {
+      "name": "Query"
+    },
+    "types": [
+      {
+        "kind": "OBJECT",
+        "name": "Query",
+        "fields": [
+          {
+            "name": "greeting",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          }
+        ]
+      },
+      {
+        "kind": "INTERFACE",
+        "name": "Foo",
+        "fields": [
+          {
+            "name": "x",
+            "type": {
+              "kind": "SCALAR",
+              "name": "Int"
+            }
+          }
+        ],
+        "interfaces": [],
+        "possibleTypes": []
+      },
+      {
+        "kind": "INTERFACE",
+        "name": "Bar",
+        "fields": [
+          {
+            "name": "x",
+            "type": {
+              "kind": "SCALAR",
+              "name": "Int"
+            }
+          },
+          {
+            "name": "y",
+            "type": {
+              "kind": "SCALAR",
+              "name": "Int"
+            },
+            "args": [
+              {
+                "name": "z",
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "Int"
+                }
+              }
+            ]
+          },
+          {
+            "name": "z",
+            "isDeprecated": true,
+            "deprecationReason": "This field is deprecated",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          }
+        ],
+        "interfaces": [
+          {
+            "kind": "INTERFACE",
+            "name": "Foo"
+          }
+        ],
+        "possibleTypes": []
+      },
+      {
+        "kind": "INPUT_OBJECT",
+        "name": "MyInput",
+        "inputFields": [
+          {
+            "name": "a",
+            "type": {
+              "kind": "SCALAR",
+              "name": "Int"
+            }
+          },
+          {
+            "name": "b",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          }
+        ]
+      },
+      {
+        "kind": "SCALAR",
+        "name": "Int",
+        "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1."
+      },
+      {
+        "kind": "SCALAR",
+        "name": "Float",
+        "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)."
+      },
+      {
+        "kind": "SCALAR",
+        "name": "String",
+        "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text."
+      },
+      {
+        "kind": "SCALAR",
+        "name": "Boolean",
+        "description": "The `Boolean` scalar type represents `true` or `false`."
+      },
+      {
+        "kind": "SCALAR",
+        "name": "ID",
+        "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID."
+      },
+      {
+        "kind": "OBJECT",
+        "name": "__Schema",
+        "fields": [
+          {
+            "name": "description",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "types",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "LIST",
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "ofType": {
+                    "kind": "OBJECT",
+                    "name": "__Type"
+                  }
+                }
+              }
+            }
+          },
+          {
+            "name": "queryType",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "__Type"
+              }
+            }
+          },
+          {
+            "name": "mutationType",
+            "type": {
+              "kind": "OBJECT",
+              "name": "__Type"
+            }
+          },
+          {
+            "name": "subscriptionType",
+            "type": {
+              "kind": "OBJECT",
+              "name": "__Type"
+            }
+          },
+          {
+            "name": "directives",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "LIST",
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "ofType": {
+                    "kind": "OBJECT",
+                    "name": "__Directive"
+                  }
+                }
+              }
+            }
+          }
+        ]
+      },
+      {
+        "kind": "OBJECT",
+        "name": "__Type",
+        "fields": [
+          {
+            "name": "kind",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "ENUM",
+                "name": "__TypeKind"
+              }
+            }
+          },
+          {
+            "name": "name",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "description",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "fields",
+            "type": {
+              "kind": "LIST",
+              "ofType": {
+                "kind": "NON_NULL",
+                "ofType": {
+                  "kind": "OBJECT",
+                  "name": "__Field"
+                }
+              }
+            },
+            "args": [
+              {
+                "name": "includeDeprecated",
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "Boolean"
+                },
+                "defaultValue": "false"
+              }
+            ]
+          },
+          {
+            "name": "interfaces",
+            "type": {
+              "kind": "LIST",
+              "ofType": {
+                "kind": "NON_NULL",
+                "ofType": {
+                  "kind": "OBJECT",
+                  "name": "__Type"
+                }
+              }
+            }
+          },
+          {
+            "name": "possibleTypes",
+            "type": {
+              "kind": "LIST",
+              "ofType": {
+                "kind": "NON_NULL",
+                "ofType": {
+                  "kind": "OBJECT",
+                  "name": "__Type"
+                }
+              }
+            }
+          },
+          {
+            "name": "enumValues",
+            "type": {
+              "kind": "LIST",
+              "ofType": {
+                "kind": "NON_NULL",
+                "ofType": {
+                  "kind": "OBJECT",
+                  "name": "__EnumValue"
+                }
+              }
+            },
+            "args": [
+              {
+                "name": "includeDeprecated",
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "Boolean"
+                },
+                "defaultValue": "false"
+              }
+            ]
+          },
+          {
+            "name": "inputFields",
+            "type": {
+              "kind": "LIST",
+              "ofType": {
+                "kind": "NON_NULL",
+                "ofType": {
+                  "kind": "OBJECT",
+                  "name": "__InputValue"
+                }
+              }
+            },
+            "args": [
+              {
+                "name": "includeDeprecated",
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "Boolean"
+                },
+                "defaultValue": "false"
+              }
+            ]
+          },
+          {
+            "name": "ofType",
+            "type": {
+              "kind": "OBJECT",
+              "name": "__Type"
+            }
+          },
+          {
+            "name": "specifiedByURL",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          }
+        ]
+      },
+      {
+        "kind": "ENUM",
+        "name": "__TypeKind",
+        "enumValues": [
+          {
+            "name": "SCALAR"
+          },
+          {
+            "name": "OBJECT"
+          },
+          {
+            "name": "INTERFACE"
+          },
+          {
+            "name": "UNION"
+          },
+          {
+            "name": "ENUM"
+          },
+          {
+            "name": "INPUT_OBJECT"
+          },
+          {
+            "name": "LIST"
+          },
+          {
+            "name": "NON_NULL"
+          }
+        ]
+      },
+      {
+        "kind": "OBJECT",
+        "name": "__Field",
+        "fields": [
+          {
+            "name": "name",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String"
+              }
+            }
+          },
+          {
+            "name": "description",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "args",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "LIST",
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "ofType": {
+                    "kind": "OBJECT",
+                    "name": "__InputValue"
+                  }
+                }
+              }
+            },
+            "args": [
+              {
+                "name": "includeDeprecated",
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "Boolean"
+                },
+                "defaultValue": "false"
+              }
+            ]
+          },
+          {
+            "name": "type",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "__Type"
+              }
+            }
+          },
+          {
+            "name": "isDeprecated",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Boolean"
+              }
+            }
+          },
+          {
+            "name": "deprecationReason",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          }
+        ]
+      },
+      {
+        "kind": "OBJECT",
+        "name": "__InputValue",
+        "fields": [
+          {
+            "name": "name",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String"
+              }
+            }
+          },
+          {
+            "name": "description",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "type",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "__Type"
+              }
+            }
+          },
+          {
+            "name": "defaultValue",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "isDeprecated",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Boolean"
+              }
+            }
+          },
+          {
+            "name": "deprecationReason",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          }
+        ]
+      },
+      {
+        "kind": "OBJECT",
+        "name": "__EnumValue",
+        "fields": [
+          {
+            "name": "name",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String"
+              }
+            }
+          },
+          {
+            "name": "description",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "isDeprecated",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Boolean"
+              }
+            }
+          },
+          {
+            "name": "deprecationReason",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          }
+        ]
+      },
+      {
+        "kind": "OBJECT",
+        "name": "__Directive",
+        "fields": [
+          {
+            "name": "name",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String"
+              }
+            }
+          },
+          {
+            "name": "description",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "locations",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "LIST",
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "ofType": {
+                    "kind": "ENUM",
+                    "name": "__DirectiveLocation"
+                  }
+                }
+              }
+            }
+          },
+          {
+            "name": "args",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "LIST",
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "ofType": {
+                    "kind": "OBJECT",
+                    "name": "__InputValue"
+                  }
+                }
+              }
+            },
+            "args": [
+              {
+                "name": "includeDeprecated",
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "Boolean"
+                },
+                "defaultValue": "false"
+              }
+            ]
+          },
+          {
+            "name": "isRepeatable",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Boolean"
+              }
+            }
+          }
+        ]
+      },
+      {
+        "kind": "ENUM",
+        "name": "__DirectiveLocation",
+        "enumValues": [
+          {
+            "name": "QUERY"
+          },
+          {
+            "name": "MUTATION"
+          },
+          {
+            "name": "SUBSCRIPTION"
+          },
+          {
+            "name": "FIELD"
+          },
+          {
+            "name": "FRAGMENT_DEFINITION"
+          },
+          {
+            "name": "FRAGMENT_SPREAD"
+          },
+          {
+            "name": "INLINE_FRAGMENT"
+          },
+          {
+            "name": "VARIABLE_DEFINITION"
+          },
+          {
+            "name": "SCHEMA"
+          },
+          {
+            "name": "SCALAR"
+          },
+          {
+            "name": "OBJECT"
+          },
+          {
+            "name": "FIELD_DEFINITION"
+          },
+          {
+            "name": "ARGUMENT_DEFINITION"
+          },
+          {
+            "name": "INTERFACE"
+          },
+          {
+            "name": "UNION"
+          },
+          {
+            "name": "ENUM"
+          },
+          {
+            "name": "ENUM_VALUE"
+          },
+          {
+            "name": "INPUT_OBJECT"
+          },
+          {
+            "name": "INPUT_FIELD_DEFINITION"
+          }
+        ]
+      }
+    ],
+    "directives": [
+      {
+        "name": "MyDirective1",
+        "args": [
+          {
+            "name": "a",
+            "type": {
+              "kind": "SCALAR",
+              "name": "Int"
+            }
+          },
+          {
+            "name": "b",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          }
+        ]
+      },
+      {
+        "name": "skip",
+        "args": [
+          {
+            "name": "if",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Boolean"
+              }
+            }
+          }
+        ]
+      },
+      {
+        "name": "include",
+        "args": [
+          {
+            "name": "if",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Boolean"
+              }
+            }
+          }
+        ]
+      },
+      {
+        "name": "deprecated",
+        "args": [
+          {
+            "name": "reason",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            },
+            "defaultValue": "\"No longer supported\""
+          }
+        ]
+      },
+      {
+        "name": "defer",
+        "args": [
+          {
+            "name": "label",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "if",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Boolean"
+              }
+            },
+            "defaultValue": "true"
+          }
+        ]
+      },
+      {
+        "name": "specifiedBy",
+        "args": [
+          {
+            "name": "url",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String"
+              }
+            }
+          }
+        ]
+      }
+    ]
+  }
+}
diff --git a/libraries/apollo-gradle-plugin/testProjects/convertSchema/schemas/schema-october-2015-spec.sdl b/libraries/apollo-gradle-plugin/testProjects/convertSchema/schemas/schema-october-2015-spec.sdl
new file mode 100644
index 0000000000..484c545731
--- /dev/null
+++ b/libraries/apollo-gradle-plugin/testProjects/convertSchema/schemas/schema-october-2015-spec.sdl
@@ -0,0 +1,194 @@
+type Query {
+  greeting: String
+}
+
+interface Foo {
+  x: Int
+}
+
+interface Bar implements Foo {
+  x: Int
+
+  y(z: Int): Int
+
+  z: String @deprecated(reason: "This field is deprecated")
+}
+
+input MyInput {
+  a: Int
+
+  b: String
+}
+
+"""
+The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
+"""
+scalar Int
+
+"""
+The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).
+"""
+scalar Float
+
+"""
+The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.
+"""
+scalar String
+
+"""
+The `Boolean` scalar type represents `true` or `false`.
+"""
+scalar Boolean
+
+"""
+The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID.
+"""
+scalar ID
+
+type __Schema {
+  description: String
+
+  types: [__Type!]!
+
+  queryType: __Type!
+
+  mutationType: __Type
+
+  subscriptionType: __Type
+
+  directives: [__Directive!]!
+}
+
+type __Type {
+  kind: __TypeKind!
+
+  name: String
+
+  description: String
+
+  fields(includeDeprecated: Boolean = false): [__Field!]
+
+  interfaces: [__Type!]
+
+  possibleTypes: [__Type!]
+
+  enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
+
+  inputFields(includeDeprecated: Boolean = false): [__InputValue!]
+
+  ofType: __Type
+
+  specifiedByURL: String
+}
+
+enum __TypeKind {
+  SCALAR
+
+  OBJECT
+
+  INTERFACE
+
+  UNION
+
+  ENUM
+
+  INPUT_OBJECT
+
+  LIST
+
+  NON_NULL
+}
+
+type __Field {
+  name: String!
+
+  description: String
+
+  args(includeDeprecated: Boolean = false): [__InputValue!]!
+
+  type: __Type!
+
+  isDeprecated: Boolean!
+
+  deprecationReason: String
+}
+
+type __InputValue {
+  name: String!
+
+  description: String
+
+  type: __Type!
+
+  defaultValue: String
+
+  isDeprecated: Boolean!
+
+  deprecationReason: String
+}
+
+type __EnumValue {
+  name: String!
+
+  description: String
+
+  isDeprecated: Boolean!
+
+  deprecationReason: String
+}
+
+type __Directive {
+  name: String!
+
+  description: String
+
+  locations: [__DirectiveLocation!]!
+
+  args(includeDeprecated: Boolean = false): [__InputValue!]!
+
+  isRepeatable: Boolean!
+}
+
+enum __DirectiveLocation {
+  QUERY
+
+  MUTATION
+
+  SUBSCRIPTION
+
+  FIELD
+
+  FRAGMENT_DEFINITION
+
+  FRAGMENT_SPREAD
+
+  INLINE_FRAGMENT
+
+  VARIABLE_DEFINITION
+
+  SCHEMA
+
+  SCALAR
+
+  OBJECT
+
+  FIELD_DEFINITION
+
+  ARGUMENT_DEFINITION
+
+  INTERFACE
+
+  UNION
+
+  ENUM
+
+  ENUM_VALUE
+
+  INPUT_OBJECT
+
+  INPUT_FIELD_DEFINITION
+}
+
+schema {
+  query: Query
+}
diff --git a/libraries/apollo-gradle-plugin/testProjects/convertSchema/schemas/schema.json b/libraries/apollo-gradle-plugin/testProjects/convertSchema/schemas/schema.json
index 598cd60b81..045d1a0d9f 100644
--- a/libraries/apollo-gradle-plugin/testProjects/convertSchema/schemas/schema.json
+++ b/libraries/apollo-gradle-plugin/testProjects/convertSchema/schemas/schema.json
@@ -1,1 +1,817 @@
-{"__schema":{"queryType":{"name":"Query"},"types":[{"kind":"OBJECT","name":"Query","fields":[{"name":"greeting","isDeprecated":false,"type":{"kind":"SCALAR","name":"String"},"args":[]}]},{"kind":"INTERFACE","name":"Foo","fields":[{"name":"x","isDeprecated":false,"type":{"kind":"SCALAR","name":"Int"},"args":[]}],"possibleTypes":[],"interfaces":[]},{"kind":"INTERFACE","name":"Bar","fields":[{"name":"x","isDeprecated":false,"type":{"kind":"SCALAR","name":"Int"},"args":[]}],"possibleTypes":[],"interfaces":[{"kind":"INTERFACE","name":"Foo","ofType":null}]},{"kind":"SCALAR","name":"Int","description":"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1."},{"kind":"SCALAR","name":"Float","description":"The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)."},{"kind":"SCALAR","name":"String","description":"The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text."},{"kind":"SCALAR","name":"Boolean","description":"The `Boolean` scalar type represents `true` or `false`."},{"kind":"SCALAR","name":"ID","description":"The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID."},{"kind":"OBJECT","name":"__Schema","fields":[{"name":"description","isDeprecated":false,"type":{"kind":"SCALAR","name":"String"},"args":[]},{"name":"types","isDeprecated":false,"type":{"kind":"NON_NULL","name":"","ofType":{"kind":"LIST","name":"","ofType":{"kind":"NON_NULL","name":"","ofType":{"kind":"OBJECT","name":"__Type"}}}},"args":[]},{"name":"queryType","isDeprecated":false,"type":{"kind":"NON_NULL","name":"","ofType":{"kind":"OBJECT","name":"__Type"}},"args":[]},{"name":"mutationType","isDeprecated":false,"type":{"kind":"OBJECT","name":"__Type"},"args":[]},{"name":"subscriptionType","isDeprecated":false,"type":{"kind":"OBJECT","name":"__Type"},"args":[]},{"name":"directives","isDeprecated":false,"type":{"kind":"NON_NULL","name":"","ofType":{"kind":"LIST","name":"","ofType":{"kind":"NON_NULL","name":"","ofType":{"kind":"OBJECT","name":"__Directive"}}}},"args":[]}]},{"kind":"OBJECT","name":"__Type","fields":[{"name":"kind","isDeprecated":false,"type":{"kind":"NON_NULL","name":"","ofType":{"kind":"ENUM","name":"__TypeKind"}},"args":[]},{"name":"name","isDeprecated":false,"type":{"kind":"SCALAR","name":"String"},"args":[]},{"name":"description","isDeprecated":false,"type":{"kind":"SCALAR","name":"String"},"args":[]},{"name":"fields","isDeprecated":false,"type":{"kind":"LIST","name":"","ofType":{"kind":"NON_NULL","name":"","ofType":{"kind":"OBJECT","name":"__Field"}}},"args":[{"name":"includeDeprecated","isDeprecated":false,"type":{"kind":"SCALAR","name":"Boolean"},"defaultValue":"false"}]},{"name":"interfaces","isDeprecated":false,"type":{"kind":"LIST","name":"","ofType":{"kind":"NON_NULL","name":"","ofType":{"kind":"OBJECT","name":"__Type"}}},"args":[]},{"name":"possibleTypes","isDeprecated":false,"type":{"kind":"LIST","name":"","ofType":{"kind":"NON_NULL","name":"","ofType":{"kind":"OBJECT","name":"__Type"}}},"args":[]},{"name":"enumValues","isDeprecated":false,"type":{"kind":"LIST","name":"","ofType":{"kind":"NON_NULL","name":"","ofType":{"kind":"OBJECT","name":"__EnumValue"}}},"args":[{"name":"includeDeprecated","isDeprecated":false,"type":{"kind":"SCALAR","name":"Boolean"},"defaultValue":"false"}]},{"name":"inputFields","isDeprecated":false,"type":{"kind":"LIST","name":"","ofType":{"kind":"NON_NULL","name":"","ofType":{"kind":"OBJECT","name":"__InputValue"}}},"args":[]},{"name":"ofType","isDeprecated":false,"type":{"kind":"OBJECT","name":"__Type"},"args":[]}]},{"kind":"OBJECT","name":"__Field","fields":[{"name":"name","isDeprecated":false,"type":{"kind":"NON_NULL","name":"","ofType":{"kind":"SCALAR","name":"String"}},"args":[]},{"name":"description","isDeprecated":false,"type":{"kind":"SCALAR","name":"String"},"args":[]},{"name":"args","isDeprecated":false,"type":{"kind":"NON_NULL","name":"","ofType":{"kind":"LIST","name":"","ofType":{"kind":"NON_NULL","name":"","ofType":{"kind":"OBJECT","name":"__InputValue"}}}},"args":[]},{"name":"type","isDeprecated":false,"type":{"kind":"NON_NULL","name":"","ofType":{"kind":"OBJECT","name":"__Type"}},"args":[]},{"name":"isDeprecated","isDeprecated":false,"type":{"kind":"NON_NULL","name":"","ofType":{"kind":"SCALAR","name":"Boolean"}},"args":[]},{"name":"deprecationReason","isDeprecated":false,"type":{"kind":"SCALAR","name":"String"},"args":[]}]},{"kind":"OBJECT","name":"__InputValue","fields":[{"name":"name","isDeprecated":false,"type":{"kind":"NON_NULL","name":"","ofType":{"kind":"SCALAR","name":"String"}},"args":[]},{"name":"description","isDeprecated":false,"type":{"kind":"SCALAR","name":"String"},"args":[]},{"name":"type","isDeprecated":false,"type":{"kind":"NON_NULL","name":"","ofType":{"kind":"OBJECT","name":"__Type"}},"args":[]},{"name":"defaultValue","isDeprecated":false,"type":{"kind":"SCALAR","name":"String"},"args":[]}]},{"kind":"OBJECT","name":"__EnumValue","fields":[{"name":"name","isDeprecated":false,"type":{"kind":"NON_NULL","name":"","ofType":{"kind":"SCALAR","name":"String"}},"args":[]},{"name":"description","isDeprecated":false,"type":{"kind":"SCALAR","name":"String"},"args":[]},{"name":"isDeprecated","isDeprecated":false,"type":{"kind":"NON_NULL","name":"","ofType":{"kind":"SCALAR","name":"Boolean"}},"args":[]},{"name":"deprecationReason","isDeprecated":false,"type":{"kind":"SCALAR","name":"String"},"args":[]}]},{"kind":"ENUM","name":"__TypeKind","enumValues":[{"name":"SCALAR","isDeprecated":false},{"name":"OBJECT","isDeprecated":false},{"name":"INTERFACE","isDeprecated":false},{"name":"UNION","isDeprecated":false},{"name":"ENUM","isDeprecated":false},{"name":"INPUT_OBJECT","isDeprecated":false},{"name":"LIST","isDeprecated":false},{"name":"NON_NULL","isDeprecated":false}]},{"kind":"OBJECT","name":"__Directive","fields":[{"name":"name","isDeprecated":false,"type":{"kind":"NON_NULL","name":"","ofType":{"kind":"SCALAR","name":"String"}},"args":[]},{"name":"description","isDeprecated":false,"type":{"kind":"SCALAR","name":"String"},"args":[]},{"name":"locations","isDeprecated":false,"type":{"kind":"NON_NULL","name":"","ofType":{"kind":"LIST","name":"","ofType":{"kind":"NON_NULL","name":"","ofType":{"kind":"ENUM","name":"__DirectiveLocation"}}}},"args":[]},{"name":"args","isDeprecated":false,"type":{"kind":"NON_NULL","name":"","ofType":{"kind":"LIST","name":"","ofType":{"kind":"NON_NULL","name":"","ofType":{"kind":"OBJECT","name":"__InputValue"}}}},"args":[]},{"name":"isRepeatable","isDeprecated":false,"type":{"kind":"NON_NULL","name":"","ofType":{"kind":"SCALAR","name":"Boolean"}},"args":[]}]},{"kind":"ENUM","name":"__DirectiveLocation","enumValues":[{"name":"QUERY","isDeprecated":false},{"name":"MUTATION","isDeprecated":false},{"name":"SUBSCRIPTION","isDeprecated":false},{"name":"FIELD","isDeprecated":false},{"name":"FRAGMENT_DEFINITION","isDeprecated":false},{"name":"FRAGMENT_SPREAD","isDeprecated":false},{"name":"INLINE_FRAGMENT","isDeprecated":false},{"name":"VARIABLE_DEFINITION","isDeprecated":false},{"name":"SCHEMA","isDeprecated":false},{"name":"SCALAR","isDeprecated":false},{"name":"OBJECT","isDeprecated":false},{"name":"FIELD_DEFINITION","isDeprecated":false},{"name":"ARGUMENT_DEFINITION","isDeprecated":false},{"name":"INTERFACE","isDeprecated":false},{"name":"UNION","isDeprecated":false},{"name":"ENUM","isDeprecated":false},{"name":"ENUM_VALUE","isDeprecated":false},{"name":"INPUT_OBJECT","isDeprecated":false},{"name":"INPUT_FIELD_DEFINITION","isDeprecated":false}]}]}}
\ No newline at end of file
+{
+  "__schema": {
+    "queryType": {
+      "name": "Query"
+    },
+    "types": [
+      {
+        "kind": "OBJECT",
+        "name": "Query",
+        "fields": [
+          {
+            "name": "greeting",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          }
+        ]
+      },
+      {
+        "kind": "INTERFACE",
+        "name": "Foo",
+        "fields": [
+          {
+            "name": "x",
+            "type": {
+              "kind": "SCALAR",
+              "name": "Int"
+            }
+          }
+        ],
+        "interfaces": [],
+        "possibleTypes": []
+      },
+      {
+        "kind": "INTERFACE",
+        "name": "Bar",
+        "fields": [
+          {
+            "name": "x",
+            "type": {
+              "kind": "SCALAR",
+              "name": "Int"
+            }
+          },
+          {
+            "name": "y",
+            "type": {
+              "kind": "SCALAR",
+              "name": "Int"
+            },
+            "args": [
+              {
+                "name": "z",
+                "isDeprecated": true,
+                "deprecationReason": "This argument is deprecated",
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "Int"
+                }
+              }
+            ]
+          },
+          {
+            "name": "z",
+            "isDeprecated": true,
+            "deprecationReason": "This field is deprecated",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          }
+        ],
+        "interfaces": [
+          {
+            "kind": "INTERFACE",
+            "name": "Foo"
+          }
+        ],
+        "possibleTypes": []
+      },
+      {
+        "kind": "INPUT_OBJECT",
+        "name": "MyInput",
+        "inputFields": [
+          {
+            "name": "a",
+            "type": {
+              "kind": "SCALAR",
+              "name": "Int"
+            }
+          },
+          {
+            "name": "b",
+            "isDeprecated": true,
+            "deprecationReason": "This input field is deprecated",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          }
+        ]
+      },
+      {
+        "kind": "SCALAR",
+        "name": "Int",
+        "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1."
+      },
+      {
+        "kind": "SCALAR",
+        "name": "Float",
+        "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)."
+      },
+      {
+        "kind": "SCALAR",
+        "name": "String",
+        "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text."
+      },
+      {
+        "kind": "SCALAR",
+        "name": "Boolean",
+        "description": "The `Boolean` scalar type represents `true` or `false`."
+      },
+      {
+        "kind": "SCALAR",
+        "name": "ID",
+        "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID."
+      },
+      {
+        "kind": "OBJECT",
+        "name": "__Schema",
+        "fields": [
+          {
+            "name": "description",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "types",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "LIST",
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "ofType": {
+                    "kind": "OBJECT",
+                    "name": "__Type"
+                  }
+                }
+              }
+            }
+          },
+          {
+            "name": "queryType",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "__Type"
+              }
+            }
+          },
+          {
+            "name": "mutationType",
+            "type": {
+              "kind": "OBJECT",
+              "name": "__Type"
+            }
+          },
+          {
+            "name": "subscriptionType",
+            "type": {
+              "kind": "OBJECT",
+              "name": "__Type"
+            }
+          },
+          {
+            "name": "directives",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "LIST",
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "ofType": {
+                    "kind": "OBJECT",
+                    "name": "__Directive"
+                  }
+                }
+              }
+            }
+          }
+        ]
+      },
+      {
+        "kind": "OBJECT",
+        "name": "__Type",
+        "fields": [
+          {
+            "name": "kind",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "ENUM",
+                "name": "__TypeKind"
+              }
+            }
+          },
+          {
+            "name": "name",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "description",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "fields",
+            "type": {
+              "kind": "LIST",
+              "ofType": {
+                "kind": "NON_NULL",
+                "ofType": {
+                  "kind": "OBJECT",
+                  "name": "__Field"
+                }
+              }
+            },
+            "args": [
+              {
+                "name": "includeDeprecated",
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "Boolean"
+                },
+                "defaultValue": "false"
+              }
+            ]
+          },
+          {
+            "name": "interfaces",
+            "type": {
+              "kind": "LIST",
+              "ofType": {
+                "kind": "NON_NULL",
+                "ofType": {
+                  "kind": "OBJECT",
+                  "name": "__Type"
+                }
+              }
+            }
+          },
+          {
+            "name": "possibleTypes",
+            "type": {
+              "kind": "LIST",
+              "ofType": {
+                "kind": "NON_NULL",
+                "ofType": {
+                  "kind": "OBJECT",
+                  "name": "__Type"
+                }
+              }
+            }
+          },
+          {
+            "name": "enumValues",
+            "type": {
+              "kind": "LIST",
+              "ofType": {
+                "kind": "NON_NULL",
+                "ofType": {
+                  "kind": "OBJECT",
+                  "name": "__EnumValue"
+                }
+              }
+            },
+            "args": [
+              {
+                "name": "includeDeprecated",
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "Boolean"
+                },
+                "defaultValue": "false"
+              }
+            ]
+          },
+          {
+            "name": "inputFields",
+            "type": {
+              "kind": "LIST",
+              "ofType": {
+                "kind": "NON_NULL",
+                "ofType": {
+                  "kind": "OBJECT",
+                  "name": "__InputValue"
+                }
+              }
+            },
+            "args": [
+              {
+                "name": "includeDeprecated",
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "Boolean"
+                },
+                "defaultValue": "false"
+              }
+            ]
+          },
+          {
+            "name": "ofType",
+            "type": {
+              "kind": "OBJECT",
+              "name": "__Type"
+            }
+          },
+          {
+            "name": "specifiedByURL",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          }
+        ]
+      },
+      {
+        "kind": "ENUM",
+        "name": "__TypeKind",
+        "enumValues": [
+          {
+            "name": "SCALAR"
+          },
+          {
+            "name": "OBJECT"
+          },
+          {
+            "name": "INTERFACE"
+          },
+          {
+            "name": "UNION"
+          },
+          {
+            "name": "ENUM"
+          },
+          {
+            "name": "INPUT_OBJECT"
+          },
+          {
+            "name": "LIST"
+          },
+          {
+            "name": "NON_NULL"
+          }
+        ]
+      },
+      {
+        "kind": "OBJECT",
+        "name": "__Field",
+        "fields": [
+          {
+            "name": "name",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String"
+              }
+            }
+          },
+          {
+            "name": "description",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "args",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "LIST",
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "ofType": {
+                    "kind": "OBJECT",
+                    "name": "__InputValue"
+                  }
+                }
+              }
+            },
+            "args": [
+              {
+                "name": "includeDeprecated",
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "Boolean"
+                },
+                "defaultValue": "false"
+              }
+            ]
+          },
+          {
+            "name": "type",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "__Type"
+              }
+            }
+          },
+          {
+            "name": "isDeprecated",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Boolean"
+              }
+            }
+          },
+          {
+            "name": "deprecationReason",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          }
+        ]
+      },
+      {
+        "kind": "OBJECT",
+        "name": "__InputValue",
+        "fields": [
+          {
+            "name": "name",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String"
+              }
+            }
+          },
+          {
+            "name": "description",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "type",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "__Type"
+              }
+            }
+          },
+          {
+            "name": "defaultValue",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "isDeprecated",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Boolean"
+              }
+            }
+          },
+          {
+            "name": "deprecationReason",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          }
+        ]
+      },
+      {
+        "kind": "OBJECT",
+        "name": "__EnumValue",
+        "fields": [
+          {
+            "name": "name",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String"
+              }
+            }
+          },
+          {
+            "name": "description",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "isDeprecated",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Boolean"
+              }
+            }
+          },
+          {
+            "name": "deprecationReason",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          }
+        ]
+      },
+      {
+        "kind": "OBJECT",
+        "name": "__Directive",
+        "fields": [
+          {
+            "name": "name",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String"
+              }
+            }
+          },
+          {
+            "name": "description",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "locations",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "LIST",
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "ofType": {
+                    "kind": "ENUM",
+                    "name": "__DirectiveLocation"
+                  }
+                }
+              }
+            }
+          },
+          {
+            "name": "args",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "LIST",
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "ofType": {
+                    "kind": "OBJECT",
+                    "name": "__InputValue"
+                  }
+                }
+              }
+            },
+            "args": [
+              {
+                "name": "includeDeprecated",
+                "type": {
+                  "kind": "SCALAR",
+                  "name": "Boolean"
+                },
+                "defaultValue": "false"
+              }
+            ]
+          },
+          {
+            "name": "isRepeatable",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Boolean"
+              }
+            }
+          }
+        ]
+      },
+      {
+        "kind": "ENUM",
+        "name": "__DirectiveLocation",
+        "enumValues": [
+          {
+            "name": "QUERY"
+          },
+          {
+            "name": "MUTATION"
+          },
+          {
+            "name": "SUBSCRIPTION"
+          },
+          {
+            "name": "FIELD"
+          },
+          {
+            "name": "FRAGMENT_DEFINITION"
+          },
+          {
+            "name": "FRAGMENT_SPREAD"
+          },
+          {
+            "name": "INLINE_FRAGMENT"
+          },
+          {
+            "name": "VARIABLE_DEFINITION"
+          },
+          {
+            "name": "SCHEMA"
+          },
+          {
+            "name": "SCALAR"
+          },
+          {
+            "name": "OBJECT"
+          },
+          {
+            "name": "FIELD_DEFINITION"
+          },
+          {
+            "name": "ARGUMENT_DEFINITION"
+          },
+          {
+            "name": "INTERFACE"
+          },
+          {
+            "name": "UNION"
+          },
+          {
+            "name": "ENUM"
+          },
+          {
+            "name": "ENUM_VALUE"
+          },
+          {
+            "name": "INPUT_OBJECT"
+          },
+          {
+            "name": "INPUT_FIELD_DEFINITION"
+          }
+        ]
+      }
+    ],
+    "directives": [
+      {
+        "name": "MyDirective1",
+        "locations": [
+          "FIELD_DEFINITION",
+          "SCALAR"
+        ],
+        "args": [
+          {
+            "name": "a",
+            "type": {
+              "kind": "SCALAR",
+              "name": "Int"
+            }
+          },
+          {
+            "name": "b",
+            "isDeprecated": true,
+            "deprecationReason": "This argument is deprecated",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          }
+        ],
+        "isRepeatable": false
+      },
+      {
+        "name": "skip",
+        "locations": [
+          "FIELD",
+          "FRAGMENT_SPREAD",
+          "INLINE_FRAGMENT"
+        ],
+        "args": [
+          {
+            "name": "if",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Boolean"
+              }
+            }
+          }
+        ],
+        "isRepeatable": false
+      },
+      {
+        "name": "include",
+        "locations": [
+          "FIELD",
+          "FRAGMENT_SPREAD",
+          "INLINE_FRAGMENT"
+        ],
+        "args": [
+          {
+            "name": "if",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Boolean"
+              }
+            }
+          }
+        ],
+        "isRepeatable": false
+      },
+      {
+        "name": "deprecated",
+        "locations": [
+          "FIELD_DEFINITION",
+          "ARGUMENT_DEFINITION",
+          "INPUT_FIELD_DEFINITION",
+          "ENUM_VALUE"
+        ],
+        "args": [
+          {
+            "name": "reason",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            },
+            "defaultValue": "\"No longer supported\""
+          }
+        ],
+        "isRepeatable": false
+      },
+      {
+        "name": "defer",
+        "locations": [
+          "FRAGMENT_SPREAD",
+          "INLINE_FRAGMENT"
+        ],
+        "args": [
+          {
+            "name": "label",
+            "type": {
+              "kind": "SCALAR",
+              "name": "String"
+            }
+          },
+          {
+            "name": "if",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Boolean"
+              }
+            },
+            "defaultValue": "true"
+          }
+        ],
+        "isRepeatable": false
+      },
+      {
+        "name": "specifiedBy",
+        "locations": [
+          "SCALAR"
+        ],
+        "args": [
+          {
+            "name": "url",
+            "type": {
+              "kind": "NON_NULL",
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String"
+              }
+            }
+          }
+        ],
+        "isRepeatable": false
+      }
+    ]
+  }
+}
diff --git a/libraries/apollo-gradle-plugin/testProjects/convertSchema/schemas/schema.sdl b/libraries/apollo-gradle-plugin/testProjects/convertSchema/schemas/schema.sdl
index 55188c7f07..15d5eff4e1 100644
--- a/libraries/apollo-gradle-plugin/testProjects/convertSchema/schemas/schema.sdl
+++ b/libraries/apollo-gradle-plugin/testProjects/convertSchema/schemas/schema.sdl
@@ -1,4 +1,3 @@
-
 type Query {
   greeting: String
 }
@@ -9,4 +8,199 @@ interface Foo {
 
 interface Bar implements Foo {
   x: Int
-}
\ No newline at end of file
+
+  y(z: Int @deprecated(reason: "This argument is deprecated")): Int
+
+  z: String @deprecated(reason: "This field is deprecated")
+}
+
+input MyInput {
+  a: Int
+
+  b: String @deprecated(reason: "This input field is deprecated")
+}
+
+"""
+The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
+"""
+scalar Int
+
+"""
+The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).
+"""
+scalar Float
+
+"""
+The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.
+"""
+scalar String
+
+"""
+The `Boolean` scalar type represents `true` or `false`.
+"""
+scalar Boolean
+
+"""
+The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID.
+"""
+scalar ID
+
+type __Schema {
+  description: String
+
+  types: [__Type!]!
+
+  queryType: __Type!
+
+  mutationType: __Type
+
+  subscriptionType: __Type
+
+  directives: [__Directive!]!
+}
+
+type __Type {
+  kind: __TypeKind!
+
+  name: String
+
+  description: String
+
+  fields(includeDeprecated: Boolean = false): [__Field!]
+
+  interfaces: [__Type!]
+
+  possibleTypes: [__Type!]
+
+  enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
+
+  inputFields(includeDeprecated: Boolean = false): [__InputValue!]
+
+  ofType: __Type
+
+  specifiedByURL: String
+}
+
+enum __TypeKind {
+  SCALAR
+
+  OBJECT
+
+  INTERFACE
+
+  UNION
+
+  ENUM
+
+  INPUT_OBJECT
+
+  LIST
+
+  NON_NULL
+}
+
+type __Field {
+  name: String!
+
+  description: String
+
+  args(includeDeprecated: Boolean = false): [__InputValue!]!
+
+  type: __Type!
+
+  isDeprecated: Boolean!
+
+  deprecationReason: String
+}
+
+type __InputValue {
+  name: String!
+
+  description: String
+
+  type: __Type!
+
+  defaultValue: String
+
+  isDeprecated: Boolean!
+
+  deprecationReason: String
+}
+
+type __EnumValue {
+  name: String!
+
+  description: String
+
+  isDeprecated: Boolean!
+
+  deprecationReason: String
+}
+
+type __Directive {
+  name: String!
+
+  description: String
+
+  locations: [__DirectiveLocation!]!
+
+  args(includeDeprecated: Boolean = false): [__InputValue!]!
+
+  isRepeatable: Boolean!
+}
+
+enum __DirectiveLocation {
+  QUERY
+
+  MUTATION
+
+  SUBSCRIPTION
+
+  FIELD
+
+  FRAGMENT_DEFINITION
+
+  FRAGMENT_SPREAD
+
+  INLINE_FRAGMENT
+
+  VARIABLE_DEFINITION
+
+  SCHEMA
+
+  SCALAR
+
+  OBJECT
+
+  FIELD_DEFINITION
+
+  ARGUMENT_DEFINITION
+
+  INTERFACE
+
+  UNION
+
+  ENUM
+
+  ENUM_VALUE
+
+  INPUT_OBJECT
+
+  INPUT_FIELD_DEFINITION
+}
+
+directive @MyDirective1 (a: Int, b: String @deprecated(reason: "This argument is deprecated")) on FIELD_DEFINITION|SCALAR
+
+directive @skip (if: Boolean!) on FIELD|FRAGMENT_SPREAD|INLINE_FRAGMENT
+
+directive @include (if: Boolean!) on FIELD|FRAGMENT_SPREAD|INLINE_FRAGMENT
+
+directive @deprecated (reason: String = "No longer supported") on FIELD_DEFINITION|ARGUMENT_DEFINITION|INPUT_FIELD_DEFINITION|ENUM_VALUE
+
+directive @defer (label: String, if: Boolean! = true) on FRAGMENT_SPREAD|INLINE_FRAGMENT
+
+directive @specifiedBy (url: String!) on SCALAR
+
+schema {
+  query: Query
+}
diff --git a/tests/include-skip-operation-based/build.gradle.kts b/tests/include-skip-operation-based/build.gradle.kts
index ef3c8d0e3c..dcbd9ac115 100644
--- a/tests/include-skip-operation-based/build.gradle.kts
+++ b/tests/include-skip-operation-based/build.gradle.kts
@@ -7,6 +7,7 @@ plugins {
 dependencies {
   implementation(golatac.lib("apollo.runtime"))
   implementation(golatac.lib("apollo.httpCache"))
+  implementation(golatac.lib("apollo.normalizedcache"))
   implementation(golatac.lib("apollo.mockserver"))
   testImplementation(golatac.lib("kotlin.test.junit"))
   testImplementation(golatac.lib("apollo.testingsupport"))
diff --git a/tests/include-skip-operation-based/src/main/graphql/operations.graphql b/tests/include-skip-operation-based/src/main/graphql/operations.graphql
index be3376e8fc..0e2da1dd0c 100644
--- a/tests/include-skip-operation-based/src/main/graphql/operations.graphql
+++ b/tests/include-skip-operation-based/src/main/graphql/operations.graphql
@@ -44,3 +44,20 @@ query GetDogSkipFalse {
 fragment dogFragment on Dog {
   barf
 }
+
+
+query GetCatIncludeVariableWithDefault($skipIf: Boolean = true) {
+  animal {
+    species @skip(if: $skipIf)
+  }
+}
+
+fragment animalFragment on Animal {
+  species @skip(if: $skipIf)
+}
+
+query SkipInFragment($skipIf: Boolean = true) {
+  animal {
+    ...animalFragment
+  }
+}
diff --git a/tests/include-skip-operation-based/src/main/graphql/schema.graphqls b/tests/include-skip-operation-based/src/main/graphql/schema.graphqls
index b0f85cd0e6..da4db93c4a 100644
--- a/tests/include-skip-operation-based/src/main/graphql/schema.graphqls
+++ b/tests/include-skip-operation-based/src/main/graphql/schema.graphqls
@@ -3,7 +3,7 @@ type Query {
 }
 
 interface Animal {
-  species: String
+  species: String!
 }
 
 type Cat implements Animal {
diff --git a/tests/include-skip-operation-based/src/test/kotlin/IncludeTest.kt b/tests/include-skip-operation-based/src/test/kotlin/IncludeTest.kt
index 10a9b30bd5..9f00bac508 100644
--- a/tests/include-skip-operation-based/src/test/kotlin/IncludeTest.kt
+++ b/tests/include-skip-operation-based/src/test/kotlin/IncludeTest.kt
@@ -1,11 +1,17 @@
+
 import com.apollographql.apollo3.api.ApolloResponse
+import com.apollographql.apollo3.api.CustomScalarAdapters
 import com.apollographql.apollo3.api.GlobalBuilder
 import com.apollographql.apollo3.api.Operation
+import com.apollographql.apollo3.api.Optional
 import com.apollographql.apollo3.api.json.MapJsonReader
 import com.apollographql.apollo3.api.parseJsonResponse
+import com.apollographql.apollo3.cache.normalized.api.TypePolicyCacheKeyGenerator
+import com.apollographql.apollo3.cache.normalized.api.normalize
 import com.example.GetCatIncludeFalseQuery
 import com.example.GetCatIncludeTrueQuery
 import com.example.GetCatIncludeVariableQuery
+import com.example.GetCatIncludeVariableWithDefaultQuery
 import com.example.GetDogSkipFalseQuery
 import com.example.GetDogSkipTrueQuery
 import com.example.GetDogSkipVariableQuery
@@ -15,6 +21,7 @@ import com.example.type.buildQuery
 import kotlinx.coroutines.runBlocking
 import kotlin.test.Test
 import kotlin.test.assertEquals
+import kotlin.test.assertNull
 
 class IncludeTest {
 
@@ -141,5 +148,32 @@ class IncludeTest {
 
     assertEquals("ouaf", response.dataAssertNoErrors.animal!!.dogFragment!!.barf)
   }
+
+  @Test
+  fun getCatIncludeVariableWithDefaultQuery(): Unit = runBlocking {
+    val operation = GetCatIncludeVariableWithDefaultQuery()
+
+    val data = GetCatIncludeVariableWithDefaultQuery.Data {
+      animal = buildCat {
+        this["species"] = Optional.Absent
+      }
+    }
+
+    operation.normalize(data, CustomScalarAdapters.Empty, TypePolicyCacheKeyGenerator)
+  }
+
+  @Test
+  fun getCatIncludeVariableWithDefaultQuery2() = runBlocking {
+    val operation = GetCatIncludeVariableWithDefaultQuery()
+
+    val data = GlobalBuilder.buildQuery {
+      animal = buildCat {
+      }
+    }
+
+    val response = operation.parseData(data)
+
+    assertNull(response.dataAssertNoErrors.animal!!.species)
+  }
 }
 
diff --git a/tests/integration-tests/src/jvmTest/kotlin/test/ApqCacheTest.kt b/tests/integration-tests/src/jvmTest/kotlin/test/ApqCacheTest.kt
index a37e3286eb..af35be0242 100644
--- a/tests/integration-tests/src/jvmTest/kotlin/test/ApqCacheTest.kt
+++ b/tests/integration-tests/src/jvmTest/kotlin/test/ApqCacheTest.kt
@@ -11,6 +11,7 @@ import com.apollographql.apollo3.mockserver.MockServer
 import com.apollographql.apollo3.testing.enqueue
 import com.apollographql.apollo3.testing.internal.runTest
 import org.junit.Test
+import kotlin.test.fail
 
 class ApqCacheTest {
   /**
@@ -26,24 +27,21 @@ class ApqCacheTest {
     mockServer.enqueue(query, data)
     mockServer.enqueue(query, data)
 
-    val apolloClient = ApolloClient.Builder()
-        .serverUrl(mockServer.url())
-        // Note that mutations will always be sent as POST requests, regardless of these settings, as to avoid hitting caches.
-        .autoPersistedQueries(
-            // For the initial hashed query that does not send the actual Graphql document
-            httpMethodForHashedQueries = HttpMethod.Get,
-            // For the follow-up query that sends the full document if the initial hashed query was not found
-            httpMethodForDocumentQueries = HttpMethod.Get
-        )
-        .normalizedCache(normalizedCacheFactory = MemoryCacheFactory(10 * 1024 * 1024))
-        .build()
-
-    // put in the cache
-    apolloClient.query(HeroNameQuery()).fetchPolicy(FetchPolicy.NetworkOnly).execute()
-
-    // Query cache and network, it shouldn't throw
-    apolloClient.query(HeroNameQuery()).fetchPolicy(FetchPolicy.CacheAndNetwork).toFlow().collect {
-      println(it.data)
+    try {
+     ApolloClient.Builder()
+          .serverUrl(mockServer.url())
+          // Note that mutations will always be sent as POST requests, regardless of these settings, as to avoid hitting caches.
+          .autoPersistedQueries(
+              // For the initial hashed query that does not send the actual Graphql document
+              httpMethodForHashedQueries = HttpMethod.Get,
+              // For the follow-up query that sends the full document if the initial hashed query was not found
+              httpMethodForDocumentQueries = HttpMethod.Get
+          )
+          .normalizedCache(normalizedCacheFactory = MemoryCacheFactory(10 * 1024 * 1024))
+          .build()
+      fail("An exception was expected")
+    } catch (e: Exception) {
+      check(e.message!!.contains("Apollo: the normalized cache must be configured before the auto persisted queries"))
     }
   }
 }