Repository: apollographql/apollo-kotlin
Pull request #4342 (2022-08-14 03:11:06)

Add a flag to disable fieldsCanMerge validation on disjoint types
re #4320

Basically, I skip `fieldsInSetCanMerge` if the `fieldOnDisjointTypesMustMerge` flag is `true`.
Please let me know if that's the expectation.

apollo-cla: @pt2121: Thank you for submitting a pull request! Before we can merge it, you'll need to sign the Apollo Contributor License Agreement here: https://contribute.apollographql.com/
netlify[bot]: ### <span aria-hidden="true">👷</span> Deploy request for *apollo-android-docs* pending review.
[Visit the deploys page to approve it](https://app.netlify.com/sites/apollo-android-docs/deploys)

|  Name | Link |
|---------------------------------|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 23e0bb9b9158eb8b86cc53fa1231eb3d5071c0d8 |
pt2121: Thanks for the feedback! I will look into them tonight.

Patch:
diff --git a/apollo-api/api/apollo-api.api b/apollo-api/api/apollo-api.api
index 60d910b363..35f514b682 100644
--- a/apollo-api/api/apollo-api.api
+++ b/apollo-api/api/apollo-api.api
@@ -723,9 +723,49 @@ public abstract class com/apollographql/apollo3/api/ObjectBuilder : com/apollogr
 
 public final class com/apollographql/apollo3/api/ObjectBuilderKt {
 	public static final fun Builder (Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Lcom/apollographql/apollo3/api/BuilderScope;
+	public static final fun adaptValue (Lcom/apollographql/apollo3/api/Adapter;Ljava/lang/Object;)Ljava/lang/Object;
 	public static final fun getGlobalBuilder ()Lcom/apollographql/apollo3/api/BuilderScope;
 }
 
+public abstract class com/apollographql/apollo3/api/ObjectMap : java/util/Map, kotlin/jvm/internal/markers/KMappedMarker {
+	public fun <init> (Ljava/util/Map;)V
+	public fun clear ()V
+	public synthetic fun compute (Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;
+	public fun compute (Ljava/lang/String;Ljava/util/function/BiFunction;)Ljava/lang/Object;
+	public synthetic fun computeIfAbsent (Ljava/lang/Object;Ljava/util/function/Function;)Ljava/lang/Object;
+	public fun computeIfAbsent (Ljava/lang/String;Ljava/util/function/Function;)Ljava/lang/Object;
+	public synthetic fun computeIfPresent (Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;
+	public fun computeIfPresent (Ljava/lang/String;Ljava/util/function/BiFunction;)Ljava/lang/Object;
+	public final fun containsKey (Ljava/lang/Object;)Z
+	public fun containsKey (Ljava/lang/String;)Z
+	public fun containsValue (Ljava/lang/Object;)Z
+	public final fun entrySet ()Ljava/util/Set;
+	public final fun get (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun get (Ljava/lang/String;)Ljava/lang/Object;
+	public fun getEntries ()Ljava/util/Set;
+	public fun getKeys ()Ljava/util/Set;
+	public fun getSize ()I
+	public fun getValues ()Ljava/util/Collection;
+	public fun isEmpty ()Z
+	public final fun keySet ()Ljava/util/Set;
+	public synthetic fun merge (Ljava/lang/Object;Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;
+	public fun merge (Ljava/lang/String;Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;
+	public synthetic fun put (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun put (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun putAll (Ljava/util/Map;)V
+	public synthetic fun putIfAbsent (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun putIfAbsent (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun remove (Ljava/lang/Object;)Ljava/lang/Object;
+	public fun remove (Ljava/lang/Object;Ljava/lang/Object;)Z
+	public synthetic fun replace (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+	public synthetic fun replace (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Z
+	public fun replace (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
+	public fun replace (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Z
+	public fun replaceAll (Ljava/util/function/BiFunction;)V
+	public final fun size ()I
+	public final fun values ()Ljava/util/Collection;
+}
+
 public final class com/apollographql/apollo3/api/ObjectType : com/apollographql/apollo3/api/CompiledNamedType {
 	public fun <init> (Ljava/lang/String;Ljava/util/List;Ljava/util/List;)V
 	public synthetic fun <init> (Ljava/lang/String;Ljava/util/List;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
diff --git a/apollo-api/src/commonMain/kotlin/com/apollographql/apollo3/api/ObjectBuilder.kt b/apollo-api/src/commonMain/kotlin/com/apollographql/apollo3/api/ObjectBuilder.kt
index 468ffdc65b..b49aa07ff9 100644
--- a/apollo-api/src/commonMain/kotlin/com/apollographql/apollo3/api/ObjectBuilder.kt
+++ b/apollo-api/src/commonMain/kotlin/com/apollographql/apollo3/api/ObjectBuilder.kt
@@ -9,7 +9,7 @@ abstract class ObjectBuilder(override val customScalarAdapters: CustomScalarAdap
 
   var __typename: String by __fields
 
-  operator fun set(key: String, value: Any) {
+  operator fun set(key: String, value: Any?) {
     __fields[key] = value
   }
 }
@@ -49,5 +49,10 @@ class BuilderProperty<T>(val adapter: Adapter<T>) {
   }
 }
 
+fun <T> adaptValue(adapter: Adapter<T>, value: T): Any? {
+  return MapJsonWriter().apply {
+    adapter.toJson(this, CustomScalarAdapters.Empty, value)
+  }.root()
+}
 
-
+abstract class ObjectMap(__fields: Map<String, Any?>): Map<String, Any?> by __fields
\ No newline at end of file
diff --git a/apollo-api/src/commonMain/kotlin/com/apollographql/apollo3/api/http/DefaultHttpRequestComposer.kt b/apollo-api/src/commonMain/kotlin/com/apollographql/apollo3/api/http/DefaultHttpRequestComposer.kt
index 67313e7969..d07f6a4313 100644
--- a/apollo-api/src/commonMain/kotlin/com/apollographql/apollo3/api/http/DefaultHttpRequestComposer.kt
+++ b/apollo-api/src/commonMain/kotlin/com/apollographql/apollo3/api/http/DefaultHttpRequestComposer.kt
@@ -38,7 +38,8 @@ class DefaultHttpRequestComposer(
 
     val requestHeaders = listOf(
         HttpHeader(HEADER_APOLLO_OPERATION_ID, operation.id()),
-        HttpHeader(HEADER_APOLLO_OPERATION_NAME, operation.name())
+        HttpHeader(HEADER_APOLLO_OPERATION_NAME, operation.name()),
+        HttpHeader(HEADER_ACCEPT_NAME, HEADER_ACCEPT_VALUE),
     ) + (apolloRequest.httpHeaders ?: emptyList())
 
     val sendApqExtensions = apolloRequest.sendApqExtensions ?: false
@@ -78,6 +79,13 @@ class DefaultHttpRequestComposer(
     // for details.
     const val HEADER_APOLLO_OPERATION_NAME = "X-APOLLO-OPERATION-NAME"
 
+    private const val HEADER_ACCEPT_NAME = "Accept"
+
+    // TODO The deferSpec=20220822 part is a temporary measure so early backend implementations of the @defer directive
+    // can recognize early client implementations and potentially reply in a compaible way.
+    // This should be removed in later versions.
+    private const val HEADER_ACCEPT_VALUE = "multipart/mixed; deferSpec=20220822, application/json"
+
     private fun <D : Operation.Data> buildGetUrl(
         serverUrl: String,
         operation: Operation<D>,
diff --git a/apollo-ast/api/apollo-ast.api b/apollo-ast/api/apollo-ast.api
index 50a1259582..7e00762fff 100644
--- a/apollo-ast/api/apollo-ast.api
+++ b/apollo-ast/api/apollo-ast.api
@@ -1010,6 +1010,8 @@ public final class com/apollographql/apollo3/ast/GqlnodeKt {
 public final class com/apollographql/apollo3/ast/GqloperationdefinitionKt {
 	public static final fun rootTypeDefinition (Lcom/apollographql/apollo3/ast/GQLOperationDefinition;Lcom/apollographql/apollo3/ast/Schema;)Lcom/apollographql/apollo3/ast/GQLTypeDefinition;
 	public static final fun validate (Lcom/apollographql/apollo3/ast/GQLOperationDefinition;Lcom/apollographql/apollo3/ast/Schema;Ljava/util/Map;)Ljava/util/List;
+	public static final fun validate (Lcom/apollographql/apollo3/ast/GQLOperationDefinition;Lcom/apollographql/apollo3/ast/Schema;Ljava/util/Map;Z)Ljava/util/List;
+	public static synthetic fun validate$default (Lcom/apollographql/apollo3/ast/GQLOperationDefinition;Lcom/apollographql/apollo3/ast/Schema;Ljava/util/Map;ZILjava/lang/Object;)Ljava/util/List;
 }
 
 public final class com/apollographql/apollo3/ast/GqlstringsKt {
diff --git a/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/api.kt b/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/api.kt
index e4e270c79e..d1455b9afd 100644
--- a/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/api.kt
+++ b/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/api.kt
@@ -2,7 +2,6 @@
 
 package com.apollographql.apollo3.ast
 
-import com.apollographql.apollo3.annotations.ApolloDeprecatedSince
 import com.apollographql.apollo3.annotations.ApolloExperimental
 import com.apollographql.apollo3.annotations.ApolloInternal
 import com.apollographql.apollo3.ast.internal.ExecutableValidationScope
@@ -27,9 +26,9 @@ fun BufferedSource.toSchema(filePath: String? = null): Schema = parseAsGQLDocume
  * See [parseAsGQLDocument] and [validateAsExecutable] for more granular error reporting
  */
 @ApolloExperimental
-fun BufferedSource.toExecutableDefinitions(schema: Schema, filePath: String? = null): List<GQLDefinition> = parseAsGQLDocument(filePath)
+fun BufferedSource.toExecutableDefinitions(schema: Schema, filePath: String? = null, fieldsOnDisjointTypesMustMerge: Boolean = true): List<GQLDefinition> = parseAsGQLDocument(filePath)
     .valueAssertNoErrors()
-    .validateAsExecutable(schema)
+    .validateAsExecutable(schema, fieldsOnDisjointTypesMustMerge)
     .valueAssertNoErrors()
 
 /**
@@ -88,12 +87,15 @@ fun GQLDocument.validateAsSchemaAndAddApolloDefinition(): GQLResult<Schema> {
 /**
  * Validates the given document as an executable document.
  *
+ * @param fieldsOnDisjointTypesMustMerge set to false to relax the standard GraphQL [FieldsInSetCanMerge](https://spec.graphql.org/draft/#FieldsInSetCanMerge())
+ * and allow fields of different types at the same Json path as long as their parent types are disjoint.
+ *
  * @return  a [GQLResult] containing the operation and fragment definitions in 'value', along with any potential issues
  */
 @ApolloExperimental
-fun GQLDocument.validateAsExecutable(schema: Schema): GQLResult<List<GQLDefinition>> {
+fun GQLDocument.validateAsExecutable(schema: Schema, fieldsOnDisjointTypesMustMerge: Boolean = true): GQLResult<List<GQLDefinition>> {
   val fragments = definitions.filterIsInstance<GQLFragmentDefinition>().associateBy { it.name }
-  val issues = ExecutableValidationScope(schema, fragments).validate(this)
+  val issues = ExecutableValidationScope(schema, fragments, fieldsOnDisjointTypesMustMerge).validate(this)
   return GQLResult(definitions, issues)
 }
 
@@ -104,6 +106,7 @@ fun GQLDocument.validateAsExecutable(schema: Schema): GQLResult<List<GQLDefiniti
 fun GQLFragmentDefinition.inferVariables(
     schema: Schema,
     fragments: Map<String, GQLFragmentDefinition>,
-) = ExecutableValidationScope(schema, fragments).inferFragmentVariables(this)
+    fieldsOnDisjointTypesMustMerge: Boolean
+) = ExecutableValidationScope(schema, fragments, fieldsOnDisjointTypesMustMerge).inferFragmentVariables(this)
 
 
diff --git a/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/gqloperationdefinition.kt b/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/gqloperationdefinition.kt
index d1f0da5a45..0a1d64602d 100644
--- a/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/gqloperationdefinition.kt
+++ b/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/gqloperationdefinition.kt
@@ -9,7 +9,9 @@ fun GQLOperationDefinition.rootTypeDefinition(schema: Schema) = when (operationT
   else -> null
 }
 
+@JvmOverloads
 fun GQLOperationDefinition.validate(
     schema: Schema,
     fragments: Map<String, GQLFragmentDefinition>,
-) = ExecutableValidationScope(schema, fragments).validateOperation(this)
\ No newline at end of file
+    fieldsOnDisjointTypesMustMerge: Boolean = true,
+) = ExecutableValidationScope(schema, fragments, fieldsOnDisjointTypesMustMerge).validateOperation(this)
\ No newline at end of file
diff --git a/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/internal/ExecutableValidationScope.kt b/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/internal/ExecutableValidationScope.kt
index 97efa00b4e..89b436294e 100644
--- a/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/internal/ExecutableValidationScope.kt
+++ b/apollo-ast/src/main/kotlin/com/apollographql/apollo3/ast/internal/ExecutableValidationScope.kt
@@ -44,10 +44,14 @@ import com.apollographql.apollo3.ast.sharesPossibleTypesWith
 /**
  * @param fragmentDefinitions: all the fragments in the current compilation unit.
  * This is required to check the type conditions as well as fields merging
+ *
+ * @param fieldsOnDisjointTypesMustMerge set to false to relax the standard GraphQL [FieldsInSetCanMerge](https://spec.graphql.org/draft/#FieldsInSetCanMerge())
+ * and allow fields of different types at the same Json path as long as their parent types are disjoint.
  */
 internal class ExecutableValidationScope(
     private val schema: Schema,
     private val fragmentDefinitions: Map<String, GQLFragmentDefinition>,
+    private val fieldsOnDisjointTypesMustMerge: Boolean,
 ) : ValidationScope {
   override val typeDefinitions = schema.typeDefinitions
   override val directiveDefinitions = schema.directiveDefinitions
@@ -240,7 +244,7 @@ internal class ExecutableValidationScope(
       validateDirective(it, this) {
         variableUsages.add(it)
       }
-      if (it.name == "experimental_defer" && !path.startsWith('-')) it.validateDeferDirective(selectionSetParent, path)
+      if (it.name == "defer" && !path.startsWith('-')) it.validateDeferDirective(selectionSetParent, path)
     }
   }
 
@@ -277,7 +281,7 @@ internal class ExecutableValidationScope(
       validateDirective(it, this) {
         variableUsages.add(it)
       }
-      if (it.name == "experimental_defer" && !path.startsWith('-')) it.validateDeferDirective(selectionSetParent, path)
+      if (it.name == "defer" && !path.startsWith('-')) it.validateDeferDirective(selectionSetParent, path)
     }
   }
 
@@ -637,6 +641,9 @@ internal class ExecutableValidationScope(
 
   // 5.3.2 2.1
   private fun haveSameResponseShape(fieldWithParentA: FieldWithParent, fieldWithParentB: FieldWithParent): Boolean {
+    if (!fieldsOnDisjointTypesMustMerge) {
+      return true
+    }
     val fieldA = fieldWithParentA.field
     val fieldB = fieldWithParentB.field
 
diff --git a/apollo-ast/src/main/resources/builtins.graphqls b/apollo-ast/src/main/resources/builtins.graphqls
index c62b6553ae..ea82981432 100644
--- a/apollo-ast/src/main/resources/builtins.graphqls
+++ b/apollo-ast/src/main/resources/builtins.graphqls
@@ -133,7 +133,7 @@ directive @deprecated(
   reason: String = "No longer supported"
 ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | ENUM_VALUE
 
-directive @experimental_defer(
+directive @defer(
   label: String
   if: Boolean
 ) on FRAGMENT_SPREAD | INLINE_FRAGMENT
diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ApolloCompiler.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ApolloCompiler.kt
index 5a68ed3116..7221e3fae4 100644
--- a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ApolloCompiler.kt
+++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ApolloCompiler.kt
@@ -83,7 +83,7 @@ object ApolloCompiler {
     val validationResult = GQLDocument(
         definitions = definitions + incomingFragments,
         filePath = null
-    ).validateAsExecutable(options.schema)
+    ).validateAsExecutable(options.schema, options.fieldsOnDisjointTypesMustMerge)
 
     validationResult.issues.checkNoErrors()
 
@@ -160,7 +160,8 @@ object ApolloCompiler {
         scalarMapping = options.scalarMapping,
         codegenModels = options.codegenModels,
         generateOptionalOperationVariables = options.generateOptionalOperationVariables,
-        generateDataBuilders = options.generateDataBuilders
+        generateDataBuilders = options.generateDataBuilders,
+        fieldsOnDisjointTypesMustMerge = options.fieldsOnDisjointTypesMustMerge
     ).build()
 
     if (debugDir != null) {
@@ -206,6 +207,7 @@ object ApolloCompiler {
             generatedSchemaName = options.generatedSchemaName,
             flatten = options.flattenModels,
             scalarMapping = options.scalarMapping,
+            generateDataBuilders = options.generateDataBuilders
         ).write(outputDir = outputDir)
       }
       else -> {
diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/Options.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/Options.kt
index 01e9549fd4..2c1eb67abe 100644
--- a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/Options.kt
+++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/Options.kt
@@ -189,7 +189,19 @@ class Options(
      */
     val addJvmOverloads: Boolean = false,
     val addTypename: String = defaultAddTypename,
-    val requiresOptInAnnotation: String? = defaultRequiresOptInAnnotation
+    val requiresOptInAnnotation: String? = defaultRequiresOptInAnnotation,
+
+    /**
+     * Whether fields with different shape are disallowed to be merged in disjoint types.
+     *
+     * Note: setting this to `false` relaxes the standard GraphQL [FieldsInSetCanMerge](https://spec.graphql.org/draft/#FieldsInSetCanMerge()) validation which may still be
+     * run on the backend.
+     *
+     * See also [issue 4320](https://github.com/apollographql/apollo-kotlin/issues/4320)
+     *
+     * Default: true.
+     */
+    val fieldsOnDisjointTypesMustMerge: Boolean = defaultFieldsOnDisjointTypesMustMerge,
 ) {
 
   /**
@@ -247,7 +259,8 @@ class Options(
       generateOptionalOperationVariables: Boolean = this.generateOptionalOperationVariables,
       addJvmOverloads: Boolean = this.addJvmOverloads,
       addTypename: String = this.addTypename,
-      requiresOptInAnnotation: String? = this.requiresOptInAnnotation
+      requiresOptInAnnotation: String? = this.requiresOptInAnnotation,
+      fieldsOnDisjointTypesMustMerge: Boolean = this.fieldsOnDisjointTypesMustMerge
   ) = Options(
       executableFiles = executableFiles,
       schema = schema,
@@ -284,6 +297,7 @@ class Options(
       addJvmOverloads = addJvmOverloads,
       addTypename = addTypename,
       requiresOptInAnnotation = requiresOptInAnnotation,
+      fieldsOnDisjointTypesMustMerge = fieldsOnDisjointTypesMustMerge
   )
 
   companion object {
@@ -314,6 +328,7 @@ class Options(
     const val defaultGenerateOptionalOperationVariables = true
     const val defaultUseSchemaPackageNameForFragments = false
     const val defaultAddJvmOverloads = false
+    const val defaultFieldsOnDisjointTypesMustMerge = true
   }
 }
 
diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/Identifiers.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/Identifiers.kt
index 46fa41aec4..663591719b 100644
--- a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/Identifiers.kt
+++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/Identifiers.kt
@@ -65,4 +65,10 @@ internal object Identifier {
    * Kotlin language identifiers
    */
   const val Companion = "Companion"
+
+  /**
+   * Java only
+   */
+  const val buildData = "buildData"
+  const val map = "map"
 }
diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/JavaClassNames.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/JavaClassNames.kt
index 9a32faf7af..58f504362a 100644
--- a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/JavaClassNames.kt
+++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/JavaClassNames.kt
@@ -1,10 +1,15 @@
 package com.apollographql.apollo3.compiler.codegen.java
 
+import com.apollographql.apollo3.api.DefaultFakeResolver
 import com.apollographql.apollo3.compiler.codegen.ClassNames
 import com.apollographql.apollo3.compiler.codegen.ClassNames.apolloApiJsonPackageName
 import com.apollographql.apollo3.compiler.codegen.ClassNames.apolloApiPackageName
 import com.apollographql.apollo3.compiler.codegen.ResolverClassName
+import com.apollographql.apollo3.compiler.codegen.kotlin.KotlinSymbols
+import com.apollographql.apollo3.compiler.codegen.kotlin.toKotlinPoetClassName
 import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.ParameterizedTypeName
+import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
 
 /**
  * A list of constant [ResolverClassName] that don't use `class.name` and therefore survive proguard/R8
@@ -45,6 +50,10 @@ internal object JavaClassNames {
   val CompiledFieldBuilder = ClassNames.CompiledFieldBuilder.toJavaPoetClassName()
   val CompiledFragment = ClassNames.CompiledFragment.toJavaPoetClassName()
   val CompiledFragmentBuilder = ClassNames.CompiledFragmentBuilder.toJavaPoetClassName()
+  val FakeResolver = ClassNames.FakeResolver.toJavaPoetClassName()
+  val FakeResolverKt = ClassName.get(apolloApiPackageName, "FakeResolverKt")
+  val DefaultFakeResolver = ClassNames.DefaultFakeResolver.toJavaPoetClassName()
+  val JavaObjectBuilder = ClassName.get(apolloApiPackageName, "JavaObjectBuilder")
 
   /**
    * ClassNames that we don't use in Kotlin because we use extension functions instead
@@ -92,4 +101,11 @@ internal object JavaClassNames {
   val Arrays = ClassName.get("java.util", "Arrays")
   val Collections = ClassName.get("java.util", "Collections")
   val IllegalStateException = ClassName.get("java.lang", "IllegalStateException")
+  val HashMap = ClassName.get("java.util", "HashMap")
+  val Map: ClassName = ClassName.get("java.util", "Map")
+  val MapOfStringToObject = ParameterizedTypeName.get(Map, String, Object)
+
+  val ObjectBuilderKt = ClassName.get(apolloApiPackageName, "ObjectBuilderKt")
+  val ObjectMap = ClassName.get(apolloApiPackageName, "ObjectMap")
+
 }
diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/JavaCodeGen.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/JavaCodeGen.kt
index 269be8f001..40c5a75415 100644
--- a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/JavaCodeGen.kt
+++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/JavaCodeGen.kt
@@ -5,6 +5,7 @@ import com.apollographql.apollo3.compiler.PackageNameGenerator
 import com.apollographql.apollo3.compiler.ScalarInfo
 import com.apollographql.apollo3.compiler.codegen.ResolverInfo
 import com.apollographql.apollo3.compiler.codegen.java.adapter.EnumResponseAdapterBuilder
+import com.apollographql.apollo3.compiler.codegen.java.file.BuilderFactoryBuilder
 import com.apollographql.apollo3.compiler.codegen.java.file.CustomScalarBuilder
 import com.apollographql.apollo3.compiler.codegen.java.file.EnumBuilder
 import com.apollographql.apollo3.compiler.codegen.java.file.FragmentBuilder
@@ -15,13 +16,17 @@ import com.apollographql.apollo3.compiler.codegen.java.file.FragmentVariablesAda
 import com.apollographql.apollo3.compiler.codegen.java.file.InputObjectAdapterBuilder
 import com.apollographql.apollo3.compiler.codegen.java.file.InputObjectBuilder
 import com.apollographql.apollo3.compiler.codegen.java.file.InterfaceBuilder
+import com.apollographql.apollo3.compiler.codegen.java.file.InterfaceMapBuilder
 import com.apollographql.apollo3.compiler.codegen.java.file.ObjectBuilder
+import com.apollographql.apollo3.compiler.codegen.java.file.ObjectBuilderBuilder
+import com.apollographql.apollo3.compiler.codegen.java.file.ObjectMapBuilder
 import com.apollographql.apollo3.compiler.codegen.java.file.OperationBuilder
 import com.apollographql.apollo3.compiler.codegen.java.file.OperationResponseAdapterBuilder
 import com.apollographql.apollo3.compiler.codegen.java.file.OperationSelectionsBuilder
 import com.apollographql.apollo3.compiler.codegen.java.file.OperationVariablesAdapterBuilder
 import com.apollographql.apollo3.compiler.codegen.java.file.SchemaBuilder
 import com.apollographql.apollo3.compiler.codegen.java.file.UnionBuilder
+import com.apollographql.apollo3.compiler.codegen.java.file.UnionMapBuilder
 import com.apollographql.apollo3.compiler.ir.Ir
 import com.apollographql.apollo3.compiler.operationoutput.OperationOutput
 import com.apollographql.apollo3.compiler.operationoutput.findOperationId
@@ -53,6 +58,7 @@ internal class JavaCodeGen(
      */
     private val flatten: Boolean,
     private val scalarMapping: Map<String, ScalarInfo>,
+    private val generateDataBuilders: Boolean
 ) {
   /**
    * @param outputDir: the directory where to write the Kotlin files
@@ -93,23 +99,32 @@ internal class JavaCodeGen(
         .filter { !context.resolver.canResolveSchemaType(it.name) }
         .forEach { obj ->
           builders.add(ObjectBuilder(context, obj))
+          if (generateDataBuilders) {
+            builders.add(ObjectBuilderBuilder(context, obj))
+            builders.add(ObjectMapBuilder(context, obj))
+          }
         }
     ir.interfaces
         .filter { !context.resolver.canResolveSchemaType(it.name) }
         .forEach { iface ->
           builders.add(InterfaceBuilder(context, iface))
+          if (generateDataBuilders) {
+            builders.add(InterfaceMapBuilder(context, iface))
+          }
         }
     ir.unions
         .filter { !context.resolver.canResolveSchemaType(it.name) }
         .forEach { union ->
           builders.add(UnionBuilder(context, union))
+          if (generateDataBuilders) {
+            builders.add(UnionMapBuilder(context, union))
+          }
         }
     ir.customScalars
         .filter { !context.resolver.canResolveSchemaType(it.name) }
         .forEach { customScalar ->
           builders.add(CustomScalarBuilder(context, customScalar))
         }
-
     ir.fragments
         .forEach { fragment ->
           builders.add(
@@ -153,17 +168,21 @@ internal class JavaCodeGen(
 
           builders.add(
               OperationBuilder(
-                  context,
-                  operationOutput.findOperationId(operation.name),
-                  generateQueryDocument,
-                  operation,
-                  flatten,
+                  context = context,
+                  operationId = operationOutput.findOperationId(operation.name),
+                  generateQueryDocument = generateQueryDocument,
+                  operation = operation,
+                  flatten = flatten,
+                  generateDataBuilders = generateDataBuilders
               )
           )
         }
 
     if (generateSchema) {
-      builders.add(SchemaBuilder(context, generatedSchemaName, ir.objects, ir.interfaces, ir.unions))
+      builders.add(SchemaBuilder(context, generatedSchemaName, ir.objects, ir.interfaces, ir.unions, ir.enums))
+    }
+    if (generateDataBuilders) {
+      builders.add(BuilderFactoryBuilder(context, ir.objects))
     }
 
     builders.forEach { it.prepare() }
diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/JavaCodegenLayout.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/JavaCodegenLayout.kt
index 4e0d2adeec..e985e949ba 100644
--- a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/JavaCodegenLayout.kt
+++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/JavaCodegenLayout.kt
@@ -24,4 +24,6 @@ internal class JavaCodegenLayout(
   // We used to write upper case enum values but the server can define different values with different cases
   // See https://github.com/apollographql/apollo-android/issues/3035
   internal fun enumValueName(name: String) = name.escapeTypeReservedWord() ?: regularIdentifier(name)
+
+  fun builderPackageName(): String = "${typePackageName()}.builder"
 }
diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/JavaResolver.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/JavaResolver.kt
index a1212ab8dc..7afa202c4a 100644
--- a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/JavaResolver.kt
+++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/JavaResolver.kt
@@ -10,19 +10,26 @@ import com.apollographql.apollo3.compiler.codegen.ResolverEntry
 import com.apollographql.apollo3.compiler.codegen.ResolverKey
 import com.apollographql.apollo3.compiler.codegen.ResolverKeyKind
 import com.apollographql.apollo3.compiler.codegen.java.adapter.singletonAdapterInitializer
+import com.apollographql.apollo3.compiler.ir.IrCompositeType2
 import com.apollographql.apollo3.compiler.ir.IrEnumType
+import com.apollographql.apollo3.compiler.ir.IrEnumType2
 import com.apollographql.apollo3.compiler.ir.IrInputObjectType
 import com.apollographql.apollo3.compiler.ir.IrListType
+import com.apollographql.apollo3.compiler.ir.IrListType2
 import com.apollographql.apollo3.compiler.ir.IrModelType
 import com.apollographql.apollo3.compiler.ir.IrNamedType
 import com.apollographql.apollo3.compiler.ir.IrNonNullType
+import com.apollographql.apollo3.compiler.ir.IrNonNullType2
 import com.apollographql.apollo3.compiler.ir.IrOptionalType
 import com.apollographql.apollo3.compiler.ir.IrScalarType
+import com.apollographql.apollo3.compiler.ir.IrScalarType2
 import com.apollographql.apollo3.compiler.ir.IrType
+import com.apollographql.apollo3.compiler.ir.IrType2
 import com.squareup.javapoet.ClassName
 import com.squareup.javapoet.CodeBlock
 import com.squareup.javapoet.ParameterizedTypeName
 import com.squareup.javapoet.TypeName
+import com.squareup.kotlinpoet.MemberName
 
 
 internal class JavaResolver(entries: List<ResolverEntry>, val next: JavaResolver?, private val scalarMapping: Map<String, ScalarInfo>) {
@@ -123,7 +130,7 @@ internal class JavaResolver(entries: List<ResolverEntry>, val next: JavaResolver
     return when (type) {
       is IrNonNullType -> error("")
       is IrListType -> {
-        CodeBlock.of("new $T<>($L)", JavaClassNames.ListAdapter, adapterInitializer(type.ofType, requiresBuffering))
+        adapterInitializer(type.ofType, requiresBuffering).listAdapter()
       }
 
       is IrScalarType -> {
@@ -240,6 +247,50 @@ internal class JavaResolver(entries: List<ResolverEntry>, val next: JavaResolver
   fun resolveSchemaType(name: String) = resolveAndAssert(ResolverKeyKind.SchemaType, name)
   fun registerSchemaType(name: String, className: ClassName) = register(ResolverKeyKind.SchemaType, name, className)
   fun registerModel(path: String, className: ClassName) = register(ResolverKeyKind.Model, path, className)
+
+  internal fun resolveIrType2(type: IrType2): TypeName {
+    return when (type) {
+      is IrNonNullType2 -> resolveIrType2(type.ofType)
+      is IrListType2 -> ParameterizedTypeName.get(JavaClassNames.List, resolveIrType2(type.ofType))
+      is IrCompositeType2 -> resolveAndAssert(ResolverKeyKind.MapType, type.name)
+      is IrEnumType2 -> resolveIrType(IrEnumType(type.name))
+      is IrScalarType2 -> resolveIrType(IrScalarType(type.name))
+    }
+  }
+
+  internal fun adapterInitializer2(type: IrType2): CodeBlock? {
+    if (type !is IrNonNullType2) {
+      return adapterInitializer2(IrNonNullType2(type))
+    }
+    return nonNullableAdapterInitializer2(type.ofType)
+  }
+
+  fun registerMapType(name: String, className: ClassName) = register(ResolverKeyKind.MapType, name, className)
+
+  private fun nonNullableAdapterInitializer2(type: IrType2): CodeBlock? {
+    return when (type) {
+      is IrNonNullType2 -> error("")
+      is IrListType2 -> adapterInitializer2(type.ofType)?.listAdapter()
+      is IrScalarType2 -> {
+        if (scalarMapping.containsKey(type.name)) {
+          nonNullableScalarAdapterInitializer(IrScalarType(type.name))
+        } else {
+          null
+        }
+      }
+      is IrEnumType2 -> {
+        nonNullableAdapterInitializer(IrEnumType(type.name), false)
+      }
+      is IrCompositeType2 -> null
+    }
+  }
+
+  private fun CodeBlock.listAdapter(): CodeBlock {
+    return CodeBlock.of("new $T<>($L)", JavaClassNames.ListAdapter, this)
+  }
+
+  fun registerSchema(className: ClassName) = register(ResolverKeyKind.Schema, "", className)
+  fun resolveSchema():ClassName = resolveAndAssert(ResolverKeyKind.Schema, "")
 }
 
 fun ResolverClassName.toJavaPoetClassName(): ClassName = ClassName.get(packageName, simpleNames[0], *simpleNames.drop(1).toTypedArray())
diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/BuilderFactoryBuilder.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/BuilderFactoryBuilder.kt
new file mode 100644
index 0000000000..c7b714ab63
--- /dev/null
+++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/BuilderFactoryBuilder.kt
@@ -0,0 +1,72 @@
+package com.apollographql.apollo3.compiler.codegen.java.file
+
+import com.apollographql.apollo3.compiler.codegen.Identifier.customScalarAdapters
+import com.apollographql.apollo3.compiler.codegen.java.CodegenJavaFile
+import com.apollographql.apollo3.compiler.codegen.java.JavaClassBuilder
+import com.apollographql.apollo3.compiler.codegen.java.JavaClassNames
+import com.apollographql.apollo3.compiler.codegen.java.JavaContext
+import com.apollographql.apollo3.compiler.codegen.java.L
+import com.apollographql.apollo3.compiler.codegen.java.T
+import com.apollographql.apollo3.compiler.ir.IrObject
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.CodeBlock
+import com.squareup.javapoet.FieldSpec
+import com.squareup.javapoet.MethodSpec
+import com.squareup.javapoet.TypeSpec
+import javax.lang.model.element.Modifier
+
+internal class BuilderFactoryBuilder(
+    private val context: JavaContext,
+    private val objs: List<IrObject>,
+) : JavaClassBuilder {
+  private val layout = context.layout
+  private val packageName = layout.builderPackageName()
+  private val simpleName = "BuilderFactory"
+
+  override fun prepare() {
+  }
+
+  override fun build(): CodegenJavaFile {
+    return CodegenJavaFile(
+        packageName = packageName,
+        typeSpec = typeSpec()
+    )
+  }
+
+  private fun typeSpec(): TypeSpec {
+    return TypeSpec
+        .classBuilder(simpleName)
+        .addModifiers(Modifier.PUBLIC)
+        .addField(JavaClassNames.CustomScalarAdapters, customScalarAdapters)
+        .addMethod(
+            MethodSpec.constructorBuilder()
+                .addModifiers(Modifier.PUBLIC)
+                .addParameter(JavaClassNames.CustomScalarAdapters, customScalarAdapters)
+                .addStatement("this.$customScalarAdapters = $customScalarAdapters")
+                .build()
+        )
+        .addMethods(
+            objs.map {
+              it.toMethodSpec()
+            }
+        )
+        .addField(
+            FieldSpec.builder(ClassName.get(packageName, simpleName), "DEFAULT")
+                .addModifiers(Modifier.STATIC, Modifier.PUBLIC)
+                .initializer(
+                    CodeBlock.of("new $L($T.PassThrough)", simpleName, JavaClassNames.CustomScalarAdapters)
+                )
+                .build()
+        )
+        .build()
+  }
+
+  private fun IrObject.toMethodSpec(): MethodSpec {
+    val builderClassName = ClassName.get(packageName, layout.objectBuilderName(name))
+    return MethodSpec.methodBuilder(layout.builderFunName(name))
+        .addModifiers(Modifier.PUBLIC)
+        .returns(builderClassName)
+        .addStatement("return new $T($customScalarAdapters)", builderClassName)
+        .build()
+  }
+}
diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/InterfaceMapBuilder.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/InterfaceMapBuilder.kt
new file mode 100644
index 0000000000..e28e8e99e6
--- /dev/null
+++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/InterfaceMapBuilder.kt
@@ -0,0 +1,41 @@
+package com.apollographql.apollo3.compiler.codegen.java.file
+
+import com.apollographql.apollo3.compiler.codegen.java.CodegenJavaFile
+import com.apollographql.apollo3.compiler.codegen.java.JavaClassBuilder
+import com.apollographql.apollo3.compiler.codegen.java.JavaContext
+import com.apollographql.apollo3.compiler.ir.IrInterface
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.TypeSpec
+import javax.lang.model.element.Modifier
+
+internal class InterfaceMapBuilder(
+    private val context: JavaContext,
+    private val iface: IrInterface,
+) : JavaClassBuilder {
+  private val layout = context.layout
+  private val packageName = layout.builderPackageName()
+  private val simpleName = layout.mapName(iface.name)
+
+  override fun prepare() {
+    context.resolver.registerMapType(iface.name, ClassName.get(packageName, simpleName))
+  }
+
+  override fun build(): CodegenJavaFile {
+    return CodegenJavaFile(
+        packageName = packageName,
+        typeSpec = iface.mapTypeSpec()
+    )
+  }
+
+  private fun IrInterface.mapTypeSpec(): TypeSpec {
+    return TypeSpec
+        .interfaceBuilder(simpleName)
+        .addModifiers(Modifier.PUBLIC)
+        .addSuperinterfaces(
+            implements.map {
+              ClassName.get(packageName, context.layout.mapName(it))
+            }
+        )
+        .build()
+  }
+}
diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/ObjectBuilderBuilder.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/ObjectBuilderBuilder.kt
new file mode 100644
index 0000000000..10a78c75cc
--- /dev/null
+++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/ObjectBuilderBuilder.kt
@@ -0,0 +1,114 @@
+package com.apollographql.apollo3.compiler.codegen.java.file
+
+import com.apollographql.apollo3.compiler.codegen.Identifier
+import com.apollographql.apollo3.compiler.codegen.Identifier.__fields
+import com.apollographql.apollo3.compiler.codegen.Identifier.customScalarAdapters
+import com.apollographql.apollo3.compiler.codegen.java.CodegenJavaFile
+import com.apollographql.apollo3.compiler.codegen.java.JavaClassBuilder
+import com.apollographql.apollo3.compiler.codegen.java.JavaClassNames
+import com.apollographql.apollo3.compiler.codegen.java.JavaContext
+import com.apollographql.apollo3.compiler.codegen.java.L
+import com.apollographql.apollo3.compiler.codegen.java.S
+import com.apollographql.apollo3.compiler.codegen.java.T
+import com.apollographql.apollo3.compiler.ir.IrMapProperty
+import com.apollographql.apollo3.compiler.ir.IrObject
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.CodeBlock
+import com.squareup.javapoet.FieldSpec
+import com.squareup.javapoet.MethodSpec
+import com.squareup.javapoet.TypeSpec
+import javax.lang.model.element.Modifier
+
+internal class ObjectBuilderBuilder(
+    private val context: JavaContext,
+    private val obj: IrObject,
+) : JavaClassBuilder {
+  private val layout = context.layout
+  private val packageName = layout.builderPackageName()
+  private val simpleName = layout.objectBuilderName(obj.name)
+  private val mapClassName = ClassName.get(packageName, layout.mapName(obj.name))
+
+  override fun prepare() {
+  }
+
+  override fun build(): CodegenJavaFile {
+    return CodegenJavaFile(
+        packageName = packageName,
+        typeSpec = obj.builderTypeSpec()
+    )
+  }
+
+  private fun IrObject.builderTypeSpec(): TypeSpec {
+    return TypeSpec
+        .classBuilder(simpleName)
+        .addModifiers(Modifier.PUBLIC)
+        .addField(JavaClassNames.CustomScalarAdapters, customScalarAdapters)
+        .addField(
+            FieldSpec.builder(JavaClassNames.MapOfStringToObject, __fields)
+                .initializer(CodeBlock.of("new $T<>()", JavaClassNames.HashMap))
+                .build()
+        )
+        .addMethod(
+            MethodSpec.constructorBuilder()
+                .addModifiers(Modifier.PUBLIC)
+                .addParameter(JavaClassNames.CustomScalarAdapters, customScalarAdapters)
+                .addStatement("this.$customScalarAdapters = $customScalarAdapters")
+                .addStatement("$__fields.put(\"__typename\", $S)", name)
+                .build()
+        )
+        .addMethods(
+            this.mapProperties.map {
+              it.toMethodSpec()
+            }
+        )
+        .addMethod(
+            aliasMethodSpec()
+        )
+        .addMethod(
+            MethodSpec.methodBuilder(Identifier.build)
+                .addModifiers(Modifier.PUBLIC)
+                .addStatement("return new $T($__fields)", mapClassName)
+                .returns(mapClassName)
+                .build()
+        )
+        .build()
+  }
+
+  private fun aliasMethodSpec(): MethodSpec {
+    return MethodSpec.methodBuilder("alias")
+        .addModifiers(Modifier.PUBLIC)
+        .returns(ClassName.get(packageName, simpleName))
+        .addParameter(JavaClassNames.String, "alias")
+        .addParameter(JavaClassNames.Object, "value")
+        .addStatement("$__fields.put(alias, value)")
+        .addStatement("return this")
+        .build()
+  }
+  private fun IrMapProperty.toMethodSpec(): MethodSpec {
+    return MethodSpec.methodBuilder(context.layout.propertyName(name))
+        .addModifiers(Modifier.PUBLIC)
+        .addParameter(context.resolver.resolveIrType2(this.type), context.layout.propertyName(name))
+        .returns(ClassName.get(packageName, simpleName))
+        .apply {
+          val adapter = context.resolver.adapterInitializer2(type)
+          val value = if (adapter != null) {
+            CodeBlock.of(
+                "$T.adaptValue($L, $L)",
+                JavaClassNames.ObjectBuilderKt,
+                context.resolver.adapterInitializer2(type),
+                context.layout.propertyName(name)
+            )
+          } else {
+            CodeBlock.of("$L", context.layout.propertyName(name))
+          }
+
+          addStatement(
+              "$__fields.put($S, $L)",
+              name,
+              value
+          )
+        }
+        .addStatement("return this")
+        .build()
+  }
+}
diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/ObjectMapBuilder.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/ObjectMapBuilder.kt
new file mode 100644
index 0000000000..d4dff90788
--- /dev/null
+++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/ObjectMapBuilder.kt
@@ -0,0 +1,58 @@
+package com.apollographql.apollo3.compiler.codegen.java.file
+
+import com.apollographql.apollo3.compiler.codegen.Identifier
+import com.apollographql.apollo3.compiler.codegen.Identifier.__fields
+import com.apollographql.apollo3.compiler.codegen.Identifier.customScalarAdapters
+import com.apollographql.apollo3.compiler.codegen.java.CodegenJavaFile
+import com.apollographql.apollo3.compiler.codegen.java.JavaClassBuilder
+import com.apollographql.apollo3.compiler.codegen.java.JavaClassNames
+import com.apollographql.apollo3.compiler.codegen.java.JavaContext
+import com.apollographql.apollo3.compiler.ir.IrCompositeType2
+import com.apollographql.apollo3.compiler.ir.IrMapProperty
+import com.apollographql.apollo3.compiler.ir.IrNonNullType2
+import com.apollographql.apollo3.compiler.ir.IrObject
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.CodeBlock
+import com.squareup.javapoet.MethodSpec
+import com.squareup.javapoet.TypeSpec
+import javax.lang.model.element.Modifier
+
+internal class ObjectMapBuilder(
+    private val context: JavaContext,
+    private val obj: IrObject,
+) : JavaClassBuilder {
+  private val layout = context.layout
+  private val packageName = layout.builderPackageName()
+  private val simpleName = layout.mapName(obj.name)
+
+  override fun prepare() {
+    context.resolver.registerMapType(obj.name, ClassName.get(packageName, simpleName))
+  }
+
+  override fun build(): CodegenJavaFile {
+    return CodegenJavaFile(
+        packageName = packageName,
+        typeSpec = obj.mapTypeSpec()
+    )
+  }
+
+  private fun IrObject.mapTypeSpec(): TypeSpec {
+    return TypeSpec
+        .classBuilder(simpleName)
+        .addModifiers(Modifier.PUBLIC)
+        .superclass(JavaClassNames.ObjectMap)
+        .addSuperinterfaces(
+            superTypes.map {
+              ClassName.get(packageName, context.layout.mapName(it))
+            }
+        )
+        .addMethod(
+            MethodSpec.constructorBuilder()
+                .addModifiers(Modifier.PUBLIC)
+                .addParameter(JavaClassNames.MapOfStringToObject, __fields)
+                .addStatement("super($__fields)")
+                .build()
+        )
+        .build()
+  }
+}
diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/OperationBuilder.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/OperationBuilder.kt
index 1bbe18b93b..fe6f8a447e 100644
--- a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/OperationBuilder.kt
+++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/OperationBuilder.kt
@@ -2,18 +2,21 @@ package com.apollographql.apollo3.compiler.codegen.java.file
 
 import com.apollographql.apollo3.ast.QueryDocumentMinifier
 import com.apollographql.apollo3.compiler.applyIf
+import com.apollographql.apollo3.compiler.codegen.Identifier
 import com.apollographql.apollo3.compiler.codegen.Identifier.OPERATION_DOCUMENT
 import com.apollographql.apollo3.compiler.codegen.Identifier.OPERATION_ID
 import com.apollographql.apollo3.compiler.codegen.Identifier.OPERATION_NAME
 import com.apollographql.apollo3.compiler.codegen.Identifier.document
 import com.apollographql.apollo3.compiler.codegen.Identifier.id
 import com.apollographql.apollo3.compiler.codegen.Identifier.name
+import com.apollographql.apollo3.compiler.codegen.Identifier.root
 import com.apollographql.apollo3.compiler.codegen.java.CodegenJavaFile
 import com.apollographql.apollo3.compiler.codegen.java.JavaClassBuilder
 import com.apollographql.apollo3.compiler.codegen.java.JavaClassNames
 import com.apollographql.apollo3.compiler.codegen.java.JavaContext
 import com.apollographql.apollo3.compiler.codegen.java.L
 import com.apollographql.apollo3.compiler.codegen.java.S
+import com.apollographql.apollo3.compiler.codegen.java.T
 import com.apollographql.apollo3.compiler.codegen.java.helpers.makeDataClassFromParameters
 import com.apollographql.apollo3.compiler.codegen.java.helpers.maybeAddDescription
 import com.apollographql.apollo3.compiler.codegen.java.helpers.toNamedType
@@ -23,6 +26,7 @@ import com.apollographql.apollo3.compiler.codegen.maybeFlatten
 import com.apollographql.apollo3.compiler.ir.IrOperation
 import com.apollographql.apollo3.compiler.ir.IrOperationType
 import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.CodeBlock
 import com.squareup.javapoet.FieldSpec
 import com.squareup.javapoet.MethodSpec
 import com.squareup.javapoet.ParameterizedTypeName
@@ -35,6 +39,7 @@ internal class OperationBuilder(
     private val operationId: String,
     private val generateQueryDocument: Boolean,
     private val operation: IrOperation,
+    private val generateDataBuilders: Boolean,
     flatten: Boolean,
 ) : JavaClassBuilder {
   private val layout = context.layout
@@ -88,6 +93,10 @@ internal class OperationBuilder(
         .addMethod(serializeVariablesMethodSpec())
         .addMethod(adapterMethodSpec(context.resolver, operation.dataProperty))
         .addMethod(rootFieldMethodSpec())
+        .applyIf(generateDataBuilders) {
+          addMethod(buildDataMethod())
+          addMethod(buildDataOverloadMethod())
+        }
         .addTypes(dataTypeSpecs())
         .addField(
             FieldSpec.builder(JavaClassNames.String, OPERATION_ID)
@@ -124,6 +133,55 @@ internal class OperationBuilder(
         .build()
   }
 
+  //  public static Data buildData(QueryMap queryMap, FakeResolver resolver) {
+//    return FakeResolverKt.buildData(
+//        GetIntQuery_ResponseAdapter.Data.INSTANCE,
+//        GetIntQuerySelections.__root,
+//        "Query",
+//        queryMap,
+//        resolver
+//    );
+//  }
+//
+//  public static Data buildData(QueryMap queryMap) {
+//    return buildData(queryMap, new DefaultFakeResolver(__Schema.types));
+//  }
+  private fun buildDataMethod(): MethodSpec {
+    return MethodSpec.methodBuilder(Identifier.buildData)
+        .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
+        .addParameter(ClassName.get(layout.builderPackageName(), layout.mapName(operation.operationType.typeName)), Identifier.map)
+        .addParameter(JavaClassNames.FakeResolver, Identifier.resolver)
+        .returns(context.resolver.resolveModel(operation.dataModelGroup.baseModelId))
+        .addCode(
+            CodeBlock.builder()
+                .add("return $T.buildData(\n", JavaClassNames.FakeResolverKt)
+                .indent()
+                .add("$L.INSTANCE,\n", context.resolver.resolveModelAdapter(operation.dataModelGroup.baseModelId))
+                .add("$T.$root,\n", context.resolver.resolveOperationSelections(operation.name))
+                .add("$S,\n", operation.operationType.typeName)
+                .add("${Identifier.map},\n")
+                .add("${Identifier.resolver}\n")
+                .unindent()
+                .add(");")
+                .build()
+        )
+        .build()
+  }
+
+  private fun buildDataOverloadMethod(): MethodSpec {
+    return MethodSpec.methodBuilder(Identifier.buildData)
+        .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
+        .addParameter(ClassName.get(layout.builderPackageName(), layout.mapName(operation.operationType.typeName)), Identifier.map)
+        .returns(context.resolver.resolveModel(operation.dataModelGroup.baseModelId))
+        .addStatement(
+            "return buildData(${Identifier.map}, new $T($T.types))",
+            JavaClassNames.DefaultFakeResolver,
+            context.resolver.resolveSchema()
+        )
+        .build()
+  }
+
+
   private fun serializeVariablesMethodSpec(): MethodSpec = serializeVariablesMethodSpec(
       adapterClassName = context.resolver.resolveOperationVariablesAdapter(operation.name),
       emptyMessage = "This operation doesn't have any variable"
diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/SchemaBuilder.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/SchemaBuilder.kt
index 940e120892..14e1b06913 100644
--- a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/SchemaBuilder.kt
+++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/SchemaBuilder.kt
@@ -9,9 +9,11 @@ import com.apollographql.apollo3.compiler.codegen.java.JavaClassNames
 import com.apollographql.apollo3.compiler.codegen.java.JavaContext
 import com.apollographql.apollo3.compiler.codegen.java.T
 import com.apollographql.apollo3.compiler.codegen.java.helpers.toListInitializerCodeblock
+import com.apollographql.apollo3.compiler.ir.IrEnum
 import com.apollographql.apollo3.compiler.ir.IrInterface
 import com.apollographql.apollo3.compiler.ir.IrObject
 import com.apollographql.apollo3.compiler.ir.IrUnion
+import com.squareup.javapoet.ClassName
 import com.squareup.javapoet.CodeBlock
 import com.squareup.javapoet.FieldSpec
 import com.squareup.javapoet.MethodSpec
@@ -25,11 +27,13 @@ internal class SchemaBuilder(
     private val objects: List<IrObject>,
     private val interfaces: List<IrInterface>,
     private val unions: List<IrUnion>,
+    private val enums: List<IrEnum>
 ) : JavaClassBuilder {
   private val layout = context.layout
   private val packageName = layout.typePackageName()
 
   override fun prepare() {
+    context.resolver.registerSchema(ClassName.get(packageName, generatedSchemaName))
   }
 
   override fun build(): CodegenJavaFile {
@@ -40,13 +44,13 @@ internal class SchemaBuilder(
   }
 
   private fun typesFieldSpec(): FieldSpec {
-    val allTypenames = interfaces.map { it.name } + objects.map { it.name } + unions.map { it.name }
+    val allTypenames = interfaces.map { it.name } + objects.map { it.name } + unions.map { it.name } + enums.map { it.name }
     val initilizer = allTypenames.sortedBy { it }.map {
       CodeBlock.of("$T.$type", context.resolver.resolveSchemaType(it))
     }.toListInitializerCodeblock(withNewLines = true)
 
     return FieldSpec.builder(
-        ParameterizedTypeName.get(JavaClassNames.List, JavaClassNames.CompiledType),
+        ParameterizedTypeName.get(JavaClassNames.List, JavaClassNames.CompiledNamedType),
         types,
     )
         .addModifiers(Modifier.STATIC)
diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/TypesBuilder.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/TypesBuilder.kt
index 963675e6ad..d0d84a65d4 100644
--- a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/TypesBuilder.kt
+++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/TypesBuilder.kt
@@ -45,7 +45,7 @@ private fun builtinScalarJavaName(name: String): String? = when (name) {
 internal fun IrEnum.typeFieldSpec(): FieldSpec {
   return FieldSpec
       .builder(JavaClassNames.EnumType, Identifier.type, Modifier.STATIC, Modifier.PUBLIC)
-      .initializer("new $T($S)", JavaClassNames.EnumType, name)
+      .initializer("new $T($S, $L)", JavaClassNames.EnumType, name, this.values.map { CodeBlock.of(S, it.name) }.toListInitializerCodeblock())
       .build()
 }
 
@@ -97,7 +97,6 @@ internal fun IrInterface.typeFieldSpec(resolver: JavaResolver): FieldSpec {
       .build()
 }
 
-
 internal fun IrUnion.typeFieldSpec(resolver: JavaResolver): FieldSpec {
   val builder = CodeBlock.builder()
   builder.add(members.map {
diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/UnionMapBuilder.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/UnionMapBuilder.kt
new file mode 100644
index 0000000000..d196dcd24d
--- /dev/null
+++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/java/file/UnionMapBuilder.kt
@@ -0,0 +1,36 @@
+package com.apollographql.apollo3.compiler.codegen.java.file
+
+import com.apollographql.apollo3.compiler.codegen.java.CodegenJavaFile
+import com.apollographql.apollo3.compiler.codegen.java.JavaClassBuilder
+import com.apollographql.apollo3.compiler.codegen.java.JavaContext
+import com.apollographql.apollo3.compiler.ir.IrUnion
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.TypeSpec
+import javax.lang.model.element.Modifier
+
+internal class UnionMapBuilder(
+    val context: JavaContext,
+    val union: IrUnion,
+) : JavaClassBuilder {
+  private val layout = context.layout
+  private val packageName = layout.builderPackageName()
+  private val simpleName = layout.mapName(union.name)
+
+  override fun prepare() {
+    context.resolver.registerMapType(union.name, ClassName.get(packageName, simpleName))
+  }
+
+  override fun build(): CodegenJavaFile {
+    return CodegenJavaFile(
+        packageName = packageName,
+        typeSpec = mapTypeSpec()
+    )
+  }
+
+  private fun mapTypeSpec(): TypeSpec {
+    return TypeSpec
+        .interfaceBuilder(simpleName)
+        .addModifiers(Modifier.PUBLIC)
+        .build()
+  }
+}
diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/kotlin/KotlinResolver.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/kotlin/KotlinResolver.kt
index 65c88c9369..f008b225d7 100644
--- a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/kotlin/KotlinResolver.kt
+++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/codegen/kotlin/KotlinResolver.kt
@@ -127,6 +127,12 @@ class KotlinResolver(
     return CodeBlock.of("%L.%M()", this, nullableFun)
   }
 
+
+  private fun CodeBlock.list(): CodeBlock {
+    val listFun = MemberName("com.apollographql.apollo3.api", "list")
+    return CodeBlock.of("%L.%M()", this, listFun)
+  }
+
   internal fun adapterInitializer2(type: IrType2): CodeBlock? {
     if (type !is IrNonNullType2) {
       return adapterInitializer2(IrNonNullType2(type))?.nullable()
@@ -134,11 +140,6 @@ class KotlinResolver(
     return nonNullableAdapterInitializer2(type.ofType)
   }
 
-  private fun CodeBlock.list(): CodeBlock {
-    val listFun = MemberName("com.apollographql.apollo3.api", "list")
-    return CodeBlock.of("%L.%M()", this, listFun)
-  }
-
   private fun nonNullableAdapterInitializer2(type: IrType2): CodeBlock? {
     return when (type) {
       is IrNonNullType2 -> error("")
diff --git a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ir/IrBuilder.kt b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ir/IrBuilder.kt
index c5650c438b..5312a97bff 100644
--- a/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ir/IrBuilder.kt
+++ b/apollo-compiler/src/main/kotlin/com/apollographql/apollo3/compiler/ir/IrBuilder.kt
@@ -74,6 +74,7 @@ internal class IrBuilder(
     private val codegenModels: String,
     private val generateOptionalOperationVariables: Boolean,
     private val generateDataBuilders: Boolean,
+    private val fieldsOnDisjointTypesMustMerge: Boolean,
 ) : FieldMerger {
   private val usedTypes = mutableListOf<String>()
 
@@ -454,7 +455,7 @@ internal class IrBuilder(
   private fun GQLFragmentDefinition.toIr(): IrFragmentDefinition {
     val typeDefinition = schema.typeDefinition(typeCondition.name)
 
-    val inferredVariables = inferVariables(schema, allFragmentDefinitions)
+    val inferredVariables = inferVariables(schema, allFragmentDefinitions, fieldsOnDisjointTypesMustMerge)
 
     val interfaceModelGroup = builder.buildFragmentInterface(
         fragmentName = name
@@ -770,7 +771,7 @@ internal fun List<GQLDirective>.toBooleanExpression(): BooleanExpression<BTerm>
 }
 
 internal fun GQLDirective.toDeferBooleanExpression(): BooleanExpression<BTerm>? {
-  if (name != "experimental_defer") return null
+  if (name != "defer") return null
   val ifArgumentValue = arguments?.arguments?.firstOrNull { it.name == "if" }?.value ?: GQLBooleanValue(value = true)
 
   val labelArgumentValue = arguments?.arguments?.firstOrNull { it.name == "label" }?.value
diff --git a/apollo-gradle-plugin-external/api/apollo-gradle-plugin-external.api b/apollo-gradle-plugin-external/api/apollo-gradle-plugin-external.api
index a3af587a94..1a1435be48 100644
--- a/apollo-gradle-plugin-external/api/apollo-gradle-plugin-external.api
+++ b/apollo-gradle-plugin-external/api/apollo-gradle-plugin-external.api
@@ -69,6 +69,7 @@ public abstract interface class com/apollographql/apollo3/gradle/api/Service {
 	public abstract fun getDebugDir ()Lorg/gradle/api/file/DirectoryProperty;
 	public abstract fun getExcludes ()Lorg/gradle/api/provider/ListProperty;
 	public abstract fun getFailOnWarnings ()Lorg/gradle/api/provider/Property;
+	public abstract fun getFieldsOnDisjointTypesMustMerge ()Lorg/gradle/api/provider/Property;
 	public abstract fun getFlattenModels ()Lorg/gradle/api/provider/Property;
 	public abstract fun getGenerateApolloMetadata ()Lorg/gradle/api/provider/Property;
 	public abstract fun getGenerateAsInternal ()Lorg/gradle/api/provider/Property;
diff --git a/apollo-gradle-plugin-external/src/main/kotlin/com/apollographql/apollo3/gradle/api/Service.kt b/apollo-gradle-plugin-external/src/main/kotlin/com/apollographql/apollo3/gradle/api/Service.kt
index c8fa768cfd..4304b95be8 100644
--- a/apollo-gradle-plugin-external/src/main/kotlin/com/apollographql/apollo3/gradle/api/Service.kt
+++ b/apollo-gradle-plugin-external/src/main/kotlin/com/apollographql/apollo3/gradle/api/Service.kt
@@ -542,6 +542,18 @@ interface Service {
   @ApolloExperimental
   val requiresOptInAnnotation: Property<String>
 
+  /**
+   * Whether fields with different shape are disallowed to be merged in disjoint types.
+   *
+   * Note: setting this to `false` relaxes the standard GraphQL [FieldsInSetCanMerge](https://spec.graphql.org/draft/#FieldsInSetCanMerge()) validation which may still be
+   * run on the backend.
+   *
+   * See also [issue 4320](https://github.com/apollographql/apollo-kotlin/issues/4320)
+   *
+   * Default: true.
+   */
+  val fieldsOnDisjointTypesMustMerge: Property<Boolean>
+
   /**
    * A shorthand method that configures defaults that match Apollo Android 2.x codegen
    *
diff --git a/apollo-gradle-plugin-external/src/main/kotlin/com/apollographql/apollo3/gradle/internal/ApolloGenerateSourcesTask.kt b/apollo-gradle-plugin-external/src/main/kotlin/com/apollographql/apollo3/gradle/internal/ApolloGenerateSourcesTask.kt
index eeda6b95b3..aea41db05e 100644
--- a/apollo-gradle-plugin-external/src/main/kotlin/com/apollographql/apollo3/gradle/internal/ApolloGenerateSourcesTask.kt
+++ b/apollo-gradle-plugin-external/src/main/kotlin/com/apollographql/apollo3/gradle/internal/ApolloGenerateSourcesTask.kt
@@ -16,6 +16,7 @@ import com.apollographql.apollo3.compiler.Options.Companion.defaultAlwaysGenerat
 import com.apollographql.apollo3.compiler.Options.Companion.defaultCodegenModels
 import com.apollographql.apollo3.compiler.Options.Companion.defaultRequiresOptInAnnotation
 import com.apollographql.apollo3.compiler.Options.Companion.defaultFailOnWarnings
+import com.apollographql.apollo3.compiler.Options.Companion.defaultFieldsOnDisjointTypesMustMerge
 import com.apollographql.apollo3.compiler.Options.Companion.defaultGenerateAsInternal
 import com.apollographql.apollo3.compiler.Options.Companion.defaultGenerateDataBuilders
 import com.apollographql.apollo3.compiler.Options.Companion.defaultGenerateFilterNotNull
@@ -209,6 +210,10 @@ abstract class ApolloGenerateSourcesTask : DefaultTask() {
   @get:Optional
   abstract val requiresOptInAnnotation: Property<String>
 
+  @get:Input
+  @get:Optional
+  abstract val fieldsOnDisjointTypesMustMerge: Property<Boolean>
+
   @TaskAction
   fun taskAction() {
     val metadata = metadataFiles.files.toList().map { ApolloMetadata.readFrom(it) }
@@ -309,6 +314,7 @@ abstract class ApolloGenerateSourcesTask : DefaultTask() {
         generateOptionalOperationVariables = generateOptionalOperationVariables.getOrElse(defaultGenerateOptionalOperationVariables),
         addJvmOverloads = addJvmOverloads.getOrElse(defaultAddJvmOverloads),
         requiresOptInAnnotation = requiresOptInAnnotation.getOrElse(defaultRequiresOptInAnnotation),
+        fieldsOnDisjointTypesMustMerge = fieldsOnDisjointTypesMustMerge.getOrElse(defaultFieldsOnDisjointTypesMustMerge)
     )
 
     val outputCompilerMetadata = ApolloCompiler.write(options)
diff --git a/apollo-gradle-plugin-external/src/main/kotlin/com/apollographql/apollo3/gradle/internal/DefaultApolloExtension.kt b/apollo-gradle-plugin-external/src/main/kotlin/com/apollographql/apollo3/gradle/internal/DefaultApolloExtension.kt
index c7cb351071..fe872730d8 100644
--- a/apollo-gradle-plugin-external/src/main/kotlin/com/apollographql/apollo3/gradle/internal/DefaultApolloExtension.kt
+++ b/apollo-gradle-plugin-external/src/main/kotlin/com/apollographql/apollo3/gradle/internal/DefaultApolloExtension.kt
@@ -572,6 +572,7 @@ abstract class DefaultApolloExtension(
       task.generateOptionalOperationVariables.set(service.generateOptionalOperationVariables)
       task.languageVersion.set(service.languageVersion)
       task.requiresOptInAnnotation.set(service.requiresOptInAnnotation)
+      task.fieldsOnDisjointTypesMustMerge.set(service.fieldsOnDisjointTypesMustMerge)
     }
   }
 
diff --git a/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/internal/DeferredJsonMerger.kt b/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/internal/DeferredJsonMerger.kt
index a62741aae2..83acb0f79e 100644
--- a/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/internal/DeferredJsonMerger.kt
+++ b/apollo-runtime/src/commonMain/kotlin/com/apollographql/apollo3/internal/DeferredJsonMerger.kt
@@ -6,6 +6,9 @@ import com.apollographql.apollo3.api.json.BufferedSourceJsonReader
 import com.apollographql.apollo3.api.json.readAny
 import okio.BufferedSource
 
+private typealias JsonMap = Map<String, Any?>
+private typealias MutableJsonMap = MutableMap<String, Any?>
+
 /**
  * Utility class for merging GraphQL JSON payloads received in multiple chunks when using the `@defer` directive.
  *
@@ -15,12 +18,15 @@ import okio.BufferedSource
  * The fields in `data` are merged into the node found in [merged] at `path` (for the first call to [merge], the payload is
  * copied to [merged] as-is).
  *
- * `errors` and `extensions` fields are not merged: they are copied as-is (if present) to the [merged] Map at each call to [merge].
+ * `errors` in incremental items (if present) are merged together in an array and then set to the `errors` field of the [merged] Map,
+ * at each call to [merge].
+ * `extensions` in incremental items (if present) are merged together in an array and then set to the `extensions/incremental` field of the
+ * [merged] Map, at each call to [merge].
  */
 @ApolloInternal
 class DeferredJsonMerger {
-  private val _merged = mutableMapOf<String, Any?>()
-  val merged: Map<String, Any?> = _merged
+  private val _merged: MutableJsonMap = mutableMapOf()
+  val merged: JsonMap = _merged
 
   private val _mergedFragmentIds = mutableSetOf<DeferredFragmentIdentifier>()
   val mergedFragmentIds: Set<DeferredFragmentIdentifier> = _mergedFragmentIds
@@ -28,56 +34,69 @@ class DeferredJsonMerger {
   var hasNext: Boolean = true
     private set
 
-  fun merge(payload: BufferedSource): Map<String, Any?> {
+  fun merge(payload: BufferedSource): JsonMap {
     val payloadMap = jsonToMap(payload)
     return merge(payloadMap)
   }
 
-  fun merge(payload: Map<String, Any?>): Map<String, Any?> {
+  @Suppress("UNCHECKED_CAST")
+  fun merge(payload: JsonMap): JsonMap {
     if (merged.isEmpty()) {
       // Initial payload, no merging needed
       _merged += payload
       return merged
     }
 
-    mergeData(payload)
-    if (payload.containsKey("errors")) {
-      _merged["errors"] = payload["errors"]
-    } else {
-      _merged.remove("errors")
-    }
-    if (payload.containsKey("extensions")) {
-      _merged["extensions"] = payload["extensions"]
-    } else {
-      _merged.remove("extensions")
+    val incrementalList = payload["incremental"] as? List<JsonMap>
+    if (incrementalList != null) {
+      val mergedErrors = mutableListOf<JsonMap>()
+      val mergedExtensions = mutableListOf<JsonMap>()
+      for (incrementalItem in incrementalList) {
+        mergeData(incrementalItem)
+        // Merge errors and extensions (if any) of the incremental list
+        (incrementalItem["errors"] as? List<JsonMap>)?.let { mergedErrors += it }
+        (incrementalItem["extensions"] as? JsonMap)?.let { mergedExtensions += it }
+      }
+      // Keep only this payload's errors and extensions, if any
+      if (mergedErrors.isNotEmpty()) {
+        _merged["errors"] = mergedErrors
+      } else {
+        _merged.remove("errors")
+      }
+      if (mergedExtensions.isNotEmpty()) {
+        _merged["extensions"] = mapOf("incremental" to mergedExtensions)
+      } else {
+        _merged.remove("extensions")
+      }
     }
 
+    hasNext = payload["hasNext"] as Boolean? ?: false
+
     return merged
   }
 
   @Suppress("UNCHECKED_CAST")
-  private fun mergeData(payloadMap: Map<String, Any?>) {
-    val payloadData = payloadMap["data"] as Map<String, Any?>?
-    val payloadPath = payloadMap["path"] as List<Any>
-    val mergedData = merged["data"] as Map<String, Any?>
-    hasNext = payloadMap["hasNext"] as Boolean? ?: false
+  private fun mergeData(incrementalItem: JsonMap) {
+    val data = incrementalItem["data"] as JsonMap?
+    val path = incrementalItem["path"] as List<Any>
+    val mergedData = merged["data"] as JsonMap
 
     // payloadData can be null if there are errors
-    if (payloadData != null) {
-      val nodeToMergeInto = nodeAtPath(mergedData, payloadPath) as MutableMap<String, Any?>
-      deepMerge(nodeToMergeInto, payloadData)
+    if (data != null) {
+      val nodeToMergeInto = nodeAtPath(mergedData, path) as MutableJsonMap
+      deepMerge(nodeToMergeInto, data)
 
-      _mergedFragmentIds += DeferredFragmentIdentifier(path = payloadPath, label = payloadMap["label"] as String?)
+      _mergedFragmentIds += DeferredFragmentIdentifier(path = path, label = incrementalItem["label"] as String?)
     }
   }
 
   @Suppress("UNCHECKED_CAST")
-  private fun deepMerge(destination: MutableMap<String, Any?>, map: Map<String, Any?>) {
+  private fun deepMerge(destination: MutableJsonMap, map: JsonMap) {
     for ((key, value) in map) {
       if (destination.containsKey(key) && destination[key] is MutableMap<*, *>) {
         // Objects: merge recursively
-        val fieldDestination = destination[key] as MutableMap<String, Any?>
-        val fieldMap = value as? Map<String, Any?> ?: error("'$key' is an object in destination but not in map")
+        val fieldDestination = destination[key] as MutableJsonMap
+        val fieldMap = value as? JsonMap ?: error("'$key' is an object in destination but not in map")
         deepMerge(destination = fieldDestination, map = fieldMap)
       } else {
         // Other types: add / overwrite
@@ -87,21 +106,21 @@ class DeferredJsonMerger {
   }
 
   @Suppress("UNCHECKED_CAST")
-  private fun jsonToMap(json: BufferedSource): Map<String, Any?> = BufferedSourceJsonReader(json).readAny() as Map<String, Any?>
+  private fun jsonToMap(json: BufferedSource): JsonMap = BufferedSourceJsonReader(json).readAny() as JsonMap
 
 
   /**
    * Find the node in the [map] at the given [path].
    * @param path The path to the node to find, as a list of either `String` (name of field in object) or `Int` (index of element in array).
    */
-  private fun nodeAtPath(map: Map<String, Any?>, path: List<Any>): Any? {
+  private fun nodeAtPath(map: JsonMap, path: List<Any>): Any? {
     var node: Any? = map
     for (key in path) {
       node = if (node is List<*>) {
         node[key as Int]
       } else {
         @Suppress("UNCHECKED_CAST")
-        node as Map<String, Any?>
+        node as JsonMap
         node[key]
       }
     }
@@ -115,6 +134,6 @@ class DeferredJsonMerger {
   }
 }
 
-internal fun Map<String, Any?>.isDeferred(): Boolean {
+internal fun JsonMap.isDeferred(): Boolean {
   return keys.contains("hasNext")
 }
diff --git a/build-logic/src/main/kotlin/Node.kt b/build-logic/src/main/kotlin/Node.kt
index c4c6b29c36..c807edc724 100644
--- a/build-logic/src/main/kotlin/Node.kt
+++ b/build-logic/src/main/kotlin/Node.kt
@@ -1,5 +1,7 @@
 import org.gradle.api.Project
 import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
+import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
+import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
 import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin
 import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension
 
@@ -23,4 +25,9 @@ fun Project.configureNode() {
       lockFileDirectory = projectDir.resolve("kotlin-js-store-${project.getKotlinPluginVersion().substringBeforeLast(".")}")
     }
   }
+
+  // See https://youtrack.jetbrains.com/issue/KT-49774/KJS-Gradle-Errors-during-NPM-dependencies-resolution-in-parallel-build-lead-to-unfriendly-error-messages-like-Projects-must-be#focus=Comments-27-6271456.0-0
+  rootProject.plugins.withType(NodeJsRootPlugin::class.java) {
+    project.extensions.getByType(NodeJsRootExtension::class.java).nodeVersion = "16.17.0"
+  }
 }
diff --git a/docs/source/tutorial/08-add-a-details-view.mdx b/docs/source/tutorial/08-add-a-details-view.mdx
index 786c9274b2..4882439ee5 100644
--- a/docs/source/tutorial/08-add-a-details-view.mdx
+++ b/docs/source/tutorial/08-add-a-details-view.mdx
@@ -9,6 +9,10 @@ In this section, you'll write a second GraphQL query that requests details about
 In `LaunchListAdapter.kt`, add a click listener:
 
 ```kotlin title="app/src/main/java/com/example/rocketreserver/LaunchListAdapter.kt"
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+        val binding = LaunchItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+        return ViewHolder(binding)
+    }
     var onEndOfListReached: (() -> Unit)? = null
     var onItemClicked: ((LaunchListQuery.Launch) -> Unit)? = null
 


Test patch:
diff --git a/apollo-compiler/src/test/graphql/com/example/__schema/java/operationBased/__schema/type/Episode.java.expected b/apollo-compiler/src/test/graphql/com/example/__schema/java/operationBased/__schema/type/Episode.java.expected
index addea7e974..0a5f1640b2 100644
--- a/apollo-compiler/src/test/graphql/com/example/__schema/java/operationBased/__schema/type/Episode.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/__schema/java/operationBased/__schema/type/Episode.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * The episodes in the Star Wars trilogy
  */
 public class Episode {
-  public static EnumType type = new EnumType("Episode");
+  public static EnumType type = new EnumType("Episode", Arrays.asList("NEWHOPE", "EMPIRE", "JEDI", "DEPRECATED", "new"));
 
   public static Episode NEWHOPE = new Episode("NEWHOPE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/__schema/java/operationBased/__schema/type/LengthUnit.java.expected b/apollo-compiler/src/test/graphql/com/example/__schema/java/operationBased/__schema/type/LengthUnit.java.expected
index b5dbb56989..ddf8746963 100644
--- a/apollo-compiler/src/test/graphql/com/example/__schema/java/operationBased/__schema/type/LengthUnit.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/__schema/java/operationBased/__schema/type/LengthUnit.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * Units of height
  */
 public class LengthUnit {
-  public static EnumType type = new EnumType("LengthUnit");
+  public static EnumType type = new EnumType("LengthUnit", Arrays.asList("METER", "FOOT"));
 
   public static LengthUnit METER = new LengthUnit("METER");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/__schema/java/operationBased/__schema/type/__Schema.java.expected b/apollo-compiler/src/test/graphql/com/example/__schema/java/operationBased/__schema/type/__Schema.java.expected
index 70d7811ae0..9d907d39cc 100644
--- a/apollo-compiler/src/test/graphql/com/example/__schema/java/operationBased/__schema/type/__Schema.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/__schema/java/operationBased/__schema/type/__Schema.java.expected
@@ -6,7 +6,6 @@
 package com.example.__schema.type;
 
 import com.apollographql.apollo3.api.CompiledNamedType;
-import com.apollographql.apollo3.api.CompiledType;
 import com.apollographql.apollo3.api.ObjectType;
 import com.apollographql.apollo3.api.PossibleTypes;
 import java.util.Arrays;
@@ -16,17 +15,19 @@ import java.util.List;
  * A Schema object containing all the composite types and a possibleTypes helper function
  */
 public class __Schema {
-  public static List<CompiledType> types = Arrays.asList(
+  public static List<CompiledNamedType> types = Arrays.asList(
     Bar.type,
     BarObject.type,
     Character.type,
     Droid.type,
+    Episode.type,
     Foo.type,
     FooBar.type,
     FooObject.type,
     FriendsConnection.type,
     FriendsEdge.type,
     Human.type,
+    LengthUnit.type,
     Mutation.type,
     PageInfo.type,
     Query.type,
@@ -34,7 +35,8 @@ public class __Schema {
     SearchResult.type,
     Starship.type,
     Tree.type,
-    TypeWithGraphQLKeywords.type
+    TypeWithGraphQLKeywords.type,
+    hero_type.type
   );
 
   public static List<ObjectType> possibleTypes(CompiledNamedType type) {
diff --git a/apollo-compiler/src/test/graphql/com/example/__schema/java/operationBased/__schema/type/hero_type.java.expected b/apollo-compiler/src/test/graphql/com/example/__schema/java/operationBased/__schema/type/hero_type.java.expected
index f3d40fed7f..5d7873163b 100644
--- a/apollo-compiler/src/test/graphql/com/example/__schema/java/operationBased/__schema/type/hero_type.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/__schema/java/operationBased/__schema/type/hero_type.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * Lower case enum type name
  */
 public class hero_type {
-  public static EnumType type = new EnumType("hero_type");
+  public static EnumType type = new EnumType("hero_type", Arrays.asList("human", "droid"));
 
   public static hero_type human = new hero_type("human");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/case_sensitive_enum/java/operationBased/case_sensitive_enum/type/Enum.java.expected b/apollo-compiler/src/test/graphql/com/example/case_sensitive_enum/java/operationBased/case_sensitive_enum/type/Enum.java.expected
index 55a8447c69..742facb649 100644
--- a/apollo-compiler/src/test/graphql/com/example/case_sensitive_enum/java/operationBased/case_sensitive_enum/type/Enum.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/case_sensitive_enum/java/operationBased/case_sensitive_enum/type/Enum.java.expected
@@ -9,9 +9,10 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 public class Enum {
-  public static EnumType type = new EnumType("Enum");
+  public static EnumType type = new EnumType("Enum", Arrays.asList("north", "North", "NORTH", "SOUTH"));
 
   public static Enum north = new Enum("north");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/deprecation/java/operationBased/deprecation/type/Episode.java.expected b/apollo-compiler/src/test/graphql/com/example/deprecation/java/operationBased/deprecation/type/Episode.java.expected
index ca6b6e2db5..fd0721e6b3 100644
--- a/apollo-compiler/src/test/graphql/com/example/deprecation/java/operationBased/deprecation/type/Episode.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/deprecation/java/operationBased/deprecation/type/Episode.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * The episodes in the Star Wars trilogy
  */
 public class Episode {
-  public static EnumType type = new EnumType("Episode");
+  public static EnumType type = new EnumType("Episode", Arrays.asList("NEWHOPE", "EMPIRE", "JEDI", "DEPRECATED", "new"));
 
   public static Episode NEWHOPE = new Episode("NEWHOPE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/enum_field/java/operationBased/enum_field/type/Gravity.java.expected b/apollo-compiler/src/test/graphql/com/example/enum_field/java/operationBased/enum_field/type/Gravity.java.expected
index fab2094227..1356c8e6e8 100644
--- a/apollo-compiler/src/test/graphql/com/example/enum_field/java/operationBased/enum_field/type/Gravity.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/enum_field/java/operationBased/enum_field/type/Gravity.java.expected
@@ -9,9 +9,10 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 public class Gravity {
-  public static EnumType type = new EnumType("Gravity");
+  public static EnumType type = new EnumType("Gravity", Arrays.asList("TOP", "CENTER", "BOTTOM", "bottom", "is", "type", "String"));
 
   public static Gravity TOP = new Gravity("TOP");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/enums_as_sealed/java/operationBased/enums_as_sealed/type/Enum.java.expected b/apollo-compiler/src/test/graphql/com/example/enums_as_sealed/java/operationBased/enums_as_sealed/type/Enum.java.expected
index e1cc181337..b7864d5f39 100644
--- a/apollo-compiler/src/test/graphql/com/example/enums_as_sealed/java/operationBased/enums_as_sealed/type/Enum.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/enums_as_sealed/java/operationBased/enums_as_sealed/type/Enum.java.expected
@@ -9,9 +9,10 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 public class Enum {
-  public static EnumType type = new EnumType("Enum");
+  public static EnumType type = new EnumType("Enum", Arrays.asList("north", "North", "NORTH", "SOUTH", "type"));
 
   public static Enum north = new Enum("north");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/fragment_with_inline_fragment/java/operationBased/fragment_with_inline_fragment/type/Episode.java.expected b/apollo-compiler/src/test/graphql/com/example/fragment_with_inline_fragment/java/operationBased/fragment_with_inline_fragment/type/Episode.java.expected
index 94da525646..5dac224eca 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragment_with_inline_fragment/java/operationBased/fragment_with_inline_fragment/type/Episode.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragment_with_inline_fragment/java/operationBased/fragment_with_inline_fragment/type/Episode.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * The episodes in the Star Wars trilogy
  */
 public class Episode {
-  public static EnumType type = new EnumType("Episode");
+  public static EnumType type = new EnumType("Episode", Arrays.asList("NEWHOPE", "EMPIRE", "JEDI", "DEPRECATED", "new"));
 
   public static Episode NEWHOPE = new Episode("NEWHOPE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/TestOperation.graphql b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/TestOperation.graphql
index 957e46a705..70da48d399 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/TestOperation.graphql
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/TestOperation.graphql
@@ -1,13 +1,13 @@
 query SpreadSingleWithDefer {
   hero {
-    ...DroidDetails @experimental_defer
+    ...DroidDetails @defer
   }
 }
 
 query SpreadMultipleWithDefer {
   hero {
-    ...DroidDetails @experimental_defer(label: "a_first")
-    ...DroidDetails @experimental_defer(label: "a_second")
+    ...DroidDetails @defer(label: "a_first")
+    ...DroidDetails @defer(label: "a_second")
   }
 }
 
@@ -15,10 +15,10 @@ query SpreadMultipleWithDeferAndInclude($cond1: Boolean!, $cond2: Boolean!, $con
   hero {
     ...DroidDetails @include(if: $cond1)
     ...DroidDetails @skip(if: $cond2)
-    ...DroidDetails @experimental_defer(label: "b_first")
-    ...DroidDetails @experimental_defer(label: "b_second")
-    ...DroidDetails @experimental_defer(label: "b_third") @include(if: $cond3)
-    ...DroidDetails @experimental_defer(label: "b_fourth") @skip(if: $cond4)
+    ...DroidDetails @defer(label: "b_first")
+    ...DroidDetails @defer(label: "b_second")
+    ...DroidDetails @defer(label: "b_third") @include(if: $cond3)
+    ...DroidDetails @defer(label: "b_fourth") @skip(if: $cond4)
   }
 }
 
@@ -28,9 +28,9 @@ fragment DroidDetails on Droid {
 
 query SpreadMultipleWithDeferWithIf($cond: Boolean!) {
   hero {
-    ...CharacterDetails @experimental_defer(label: "c_first" if: false)
-    ...CharacterDetails2 @experimental_defer(label: "c_second" if: true)
-    ...CharacterDetails3 @experimental_defer(label: "c_third" if: $cond)
+    ...CharacterDetails @defer(label: "c_first" if: false)
+    ...CharacterDetails2 @defer(label: "c_second" if: true)
+    ...CharacterDetails3 @defer(label: "c_third" if: $cond)
   }
 }
 
@@ -48,7 +48,7 @@ fragment CharacterDetails3 on Droid {
 
 query InlineSingleWithDefer {
   hero {
-    ... on Droid @experimental_defer {
+    ... on Droid @defer {
       name
     }
   }
@@ -56,11 +56,11 @@ query InlineSingleWithDefer {
 
 query InlineMultipleWithDefer {
   hero {
-    ... on Droid @experimental_defer(label: "d_first") {
+    ... on Droid @defer(label: "d_first") {
       name
     }
 
-    ... on Droid @experimental_defer(label: "d_second") {
+    ... on Droid @defer(label: "d_second") {
       id
     }
   }
@@ -74,16 +74,16 @@ query InlineMultipleWithDeferAndInclude($cond1: Boolean!, $cond2: Boolean!, $con
     ... on Droid @skip(if: $cond2) {
       id
     }
-    ... on Droid @experimental_defer(label: "e_first") {
+    ... on Droid @defer(label: "e_first") {
       name
     }
-    ... on Droid @experimental_defer(label: "e_second") {
+    ... on Droid @defer(label: "e_second") {
       id
     }
-    ... on Droid @experimental_defer(label: "e_third") @include(if: $cond3) {
+    ... on Droid @defer(label: "e_third") @include(if: $cond3) {
       name
     }
-    ... on Droid @experimental_defer(label: "e_fourth") @skip(if: $cond4) {
+    ... on Droid @defer(label: "e_fourth") @skip(if: $cond4) {
       id
     }
   }
@@ -91,15 +91,15 @@ query InlineMultipleWithDeferAndInclude($cond1: Boolean!, $cond2: Boolean!, $con
 
 query InlineMultipleWithDeferWithIf($cond: Boolean!) {
   hero {
-    ... on Character @experimental_defer(label: "f_first" if: false) {
+    ... on Character @defer(label: "f_first" if: false) {
       id
     }
 
-    ... on Character @experimental_defer(label: "f_second" if: true) {
+    ... on Character @defer(label: "f_second" if: true) {
       name
     }
 
-    ... on Character @experimental_defer(label: "f_third" if: $cond) {
+    ... on Character @defer(label: "f_third" if: $cond) {
       name
     }
   }
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDefer.java.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDefer.java.expected
index b5148d72e2..7aaae05a22 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDefer.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDefer.java.expected
@@ -19,7 +19,7 @@ import java.lang.Override;
 import java.lang.String;
 
 public class InlineMultipleWithDefer implements Query<InlineMultipleWithDefer.Data> {
-  public static final String OPERATION_ID = "9811408b41402ad913abcd7bb5ce221d926a3c545f3f401706b25aefa816081e";
+  public static final String OPERATION_ID = "9331f0c719bafb010d29f76c720d4488f45c5196bf3fb8908b2be30bc546e355";
 
   /**
    * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -28,16 +28,16 @@ public class InlineMultipleWithDefer implements Query<InlineMultipleWithDefer.Da
    * query InlineMultipleWithDefer {
    *   hero {
    *     __typename
-   *     ... on Droid @experimental_defer(label: "d_first") {
+   *     ... on Droid @defer(label: "d_first") {
    *       name
    *     }
-   *     ... on Droid @experimental_defer(label: "d_second") {
+   *     ... on Droid @defer(label: "d_second") {
    *       id
    *     }
    *   }
    * }
    */
-  public static final String OPERATION_DOCUMENT = "query InlineMultipleWithDefer { hero { __typename ... on Droid @experimental_defer(label: \"d_first\") { name } ... on Droid @experimental_defer(label: \"d_second\") { id } } }";
+  public static final String OPERATION_DOCUMENT = "query InlineMultipleWithDefer { hero { __typename ... on Droid @defer(label: \"d_first\") { name } ... on Droid @defer(label: \"d_second\") { id } } }";
 
   public static final String OPERATION_NAME = "InlineMultipleWithDefer";
 
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDeferAndInclude.java.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDeferAndInclude.java.expected
index 8bb3680a35..deca3a7a67 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDeferAndInclude.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDeferAndInclude.java.expected
@@ -21,7 +21,7 @@ import java.lang.Override;
 import java.lang.String;
 
 public class InlineMultipleWithDeferAndInclude implements Query<InlineMultipleWithDeferAndInclude.Data> {
-  public static final String OPERATION_ID = "90fbc93ce8710e768303863f05c634101ecab0723c10e370c3b8c643ff30f96e";
+  public static final String OPERATION_ID = "f159c1ac4f33a49c5c9833e06a2606e2fc7ede812e119909eb45f95dc2aa01fc";
 
   /**
    * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -36,22 +36,22 @@ public class InlineMultipleWithDeferAndInclude implements Query<InlineMultipleWi
    *     ... on Droid @skip(if: $cond2) {
    *       id
    *     }
-   *     ... on Droid @experimental_defer(label: "e_first") {
+   *     ... on Droid @defer(label: "e_first") {
    *       name
    *     }
-   *     ... on Droid @experimental_defer(label: "e_second") {
+   *     ... on Droid @defer(label: "e_second") {
    *       id
    *     }
-   *     ... on Droid @experimental_defer(label: "e_third") @include(if: $cond3) {
+   *     ... on Droid @defer(label: "e_third") @include(if: $cond3) {
    *       name
    *     }
-   *     ... on Droid @experimental_defer(label: "e_fourth") @skip(if: $cond4) {
+   *     ... on Droid @defer(label: "e_fourth") @skip(if: $cond4) {
    *       id
    *     }
    *   }
    * }
    */
-  public static final String OPERATION_DOCUMENT = "query InlineMultipleWithDeferAndInclude($cond1: Boolean!, $cond2: Boolean!, $cond3: Boolean!, $cond4: Boolean!) { hero { __typename ... on Droid @include(if: $cond1) { name } ... on Droid @skip(if: $cond2) { id } ... on Droid @experimental_defer(label: \"e_first\") { name } ... on Droid @experimental_defer(label: \"e_second\") { id } ... on Droid @experimental_defer(label: \"e_third\") @include(if: $cond3) { name } ... on Droid @experimental_defer(label: \"e_fourth\") @skip(if: $cond4) { id } } }";
+  public static final String OPERATION_DOCUMENT = "query InlineMultipleWithDeferAndInclude($cond1: Boolean!, $cond2: Boolean!, $cond3: Boolean!, $cond4: Boolean!) { hero { __typename ... on Droid @include(if: $cond1) { name } ... on Droid @skip(if: $cond2) { id } ... on Droid @defer(label: \"e_first\") { name } ... on Droid @defer(label: \"e_second\") { id } ... on Droid @defer(label: \"e_third\") @include(if: $cond3) { name } ... on Droid @defer(label: \"e_fourth\") @skip(if: $cond4) { id } } }";
 
   public static final String OPERATION_NAME = "InlineMultipleWithDeferAndInclude";
 
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDeferWithIf.java.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDeferWithIf.java.expected
index 2ca5b7a5f5..76748030c9 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDeferWithIf.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDeferWithIf.java.expected
@@ -21,7 +21,7 @@ import java.lang.Override;
 import java.lang.String;
 
 public class InlineMultipleWithDeferWithIf implements Query<InlineMultipleWithDeferWithIf.Data> {
-  public static final String OPERATION_ID = "3e777ab8534ca2847df43e92a828787127e9536d7c1ab8136985620443c2b991";
+  public static final String OPERATION_ID = "9dc79c78df7375c3d860d16df3ea839ea45c7f8420976f63414610d338f0caf1";
 
   /**
    * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -30,19 +30,19 @@ public class InlineMultipleWithDeferWithIf implements Query<InlineMultipleWithDe
    * query InlineMultipleWithDeferWithIf($cond: Boolean!) {
    *   hero {
    *     __typename
-   *     ... on Character @experimental_defer(label: "f_first", if: false) {
+   *     ... on Character @defer(label: "f_first", if: false) {
    *       id
    *     }
-   *     ... on Character @experimental_defer(label: "f_second", if: true) {
+   *     ... on Character @defer(label: "f_second", if: true) {
    *       name
    *     }
-   *     ... on Character @experimental_defer(label: "f_third", if: $cond) {
+   *     ... on Character @defer(label: "f_third", if: $cond) {
    *       name
    *     }
    *   }
    * }
    */
-  public static final String OPERATION_DOCUMENT = "query InlineMultipleWithDeferWithIf($cond: Boolean!) { hero { __typename ... on Character @experimental_defer(label: \"f_first\", if: false) { id } ... on Character @experimental_defer(label: \"f_second\", if: true) { name } ... on Character @experimental_defer(label: \"f_third\", if: $cond) { name } } }";
+  public static final String OPERATION_DOCUMENT = "query InlineMultipleWithDeferWithIf($cond: Boolean!) { hero { __typename ... on Character @defer(label: \"f_first\", if: false) { id } ... on Character @defer(label: \"f_second\", if: true) { name } ... on Character @defer(label: \"f_third\", if: $cond) { name } } }";
 
   public static final String OPERATION_NAME = "InlineMultipleWithDeferWithIf";
 
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/InlineSingleWithDefer.java.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/InlineSingleWithDefer.java.expected
index 44a87c6d5a..59ebfd4837 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/InlineSingleWithDefer.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/InlineSingleWithDefer.java.expected
@@ -19,7 +19,7 @@ import java.lang.Override;
 import java.lang.String;
 
 public class InlineSingleWithDefer implements Query<InlineSingleWithDefer.Data> {
-  public static final String OPERATION_ID = "da1ea6b7b54f4bc6e0754b9bbe45a002500fef00de7f3605a4efd02133c20def";
+  public static final String OPERATION_ID = "70222802c9192f810f19a54d31e039ce0fc3b8baac231841f0a0e8b4200c312b";
 
   /**
    * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -28,13 +28,13 @@ public class InlineSingleWithDefer implements Query<InlineSingleWithDefer.Data>
    * query InlineSingleWithDefer {
    *   hero {
    *     __typename
-   *     ... on Droid @experimental_defer {
+   *     ... on Droid @defer {
    *       name
    *     }
    *   }
    * }
    */
-  public static final String OPERATION_DOCUMENT = "query InlineSingleWithDefer { hero { __typename ... on Droid @experimental_defer { name } } }";
+  public static final String OPERATION_DOCUMENT = "query InlineSingleWithDefer { hero { __typename ... on Droid @defer { name } } }";
 
   public static final String OPERATION_NAME = "InlineSingleWithDefer";
 
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDefer.java.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDefer.java.expected
index 66d7236488..efa69b0ab6 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDefer.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDefer.java.expected
@@ -20,7 +20,7 @@ import java.lang.Override;
 import java.lang.String;
 
 public class SpreadMultipleWithDefer implements Query<SpreadMultipleWithDefer.Data> {
-  public static final String OPERATION_ID = "e52d7b5c6a99f54c7d8e7f1d6c4f6e604586b4c83b212436661068e98f4f7ad1";
+  public static final String OPERATION_ID = "7cd4d1b6a14f96cff4bbbdbd3b3ab1aa365ffc65e1515ff6e22935010543ad71";
 
   /**
    * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -29,8 +29,8 @@ public class SpreadMultipleWithDefer implements Query<SpreadMultipleWithDefer.Da
    * query SpreadMultipleWithDefer {
    *   hero {
    *     __typename
-   *     ...DroidDetails @experimental_defer(label: "a_first")
-   *     ...DroidDetails @experimental_defer(label: "a_second")
+   *     ...DroidDetails @defer(label: "a_first")
+   *     ...DroidDetails @defer(label: "a_second")
    *   }
    * }
    *
@@ -38,7 +38,7 @@ public class SpreadMultipleWithDefer implements Query<SpreadMultipleWithDefer.Da
    *   name
    * }
    */
-  public static final String OPERATION_DOCUMENT = "query SpreadMultipleWithDefer { hero { __typename ...DroidDetails @experimental_defer(label: \"a_first\") ...DroidDetails @experimental_defer(label: \"a_second\") } }  fragment DroidDetails on Droid { name }";
+  public static final String OPERATION_DOCUMENT = "query SpreadMultipleWithDefer { hero { __typename ...DroidDetails @defer(label: \"a_first\") ...DroidDetails @defer(label: \"a_second\") } }  fragment DroidDetails on Droid { name }";
 
   public static final String OPERATION_NAME = "SpreadMultipleWithDefer";
 
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferAndInclude.java.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferAndInclude.java.expected
index 3f6a1332e1..5c49d67940 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferAndInclude.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferAndInclude.java.expected
@@ -22,7 +22,7 @@ import java.lang.Override;
 import java.lang.String;
 
 public class SpreadMultipleWithDeferAndInclude implements Query<SpreadMultipleWithDeferAndInclude.Data> {
-  public static final String OPERATION_ID = "de31db86e7b05f57e3d3d700a4811e4aba6c56860dc18f94879165a5e04fcfe8";
+  public static final String OPERATION_ID = "1c9d61b4af65df2bfed92353244efbb66d20a35daf747507e66ed9d20dcd1517";
 
   /**
    * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -33,10 +33,10 @@ public class SpreadMultipleWithDeferAndInclude implements Query<SpreadMultipleWi
    *     __typename
    *     ...DroidDetails @include(if: $cond1)
    *     ...DroidDetails @skip(if: $cond2)
-   *     ...DroidDetails @experimental_defer(label: "b_first")
-   *     ...DroidDetails @experimental_defer(label: "b_second")
-   *     ...DroidDetails @experimental_defer(label: "b_third") @include(if: $cond3)
-   *     ...DroidDetails @experimental_defer(label: "b_fourth") @skip(if: $cond4)
+   *     ...DroidDetails @defer(label: "b_first")
+   *     ...DroidDetails @defer(label: "b_second")
+   *     ...DroidDetails @defer(label: "b_third") @include(if: $cond3)
+   *     ...DroidDetails @defer(label: "b_fourth") @skip(if: $cond4)
    *   }
    * }
    *
@@ -44,7 +44,7 @@ public class SpreadMultipleWithDeferAndInclude implements Query<SpreadMultipleWi
    *   name
    * }
    */
-  public static final String OPERATION_DOCUMENT = "query SpreadMultipleWithDeferAndInclude($cond1: Boolean!, $cond2: Boolean!, $cond3: Boolean!, $cond4: Boolean!) { hero { __typename ...DroidDetails @include(if: $cond1) ...DroidDetails @skip(if: $cond2) ...DroidDetails @experimental_defer(label: \"b_first\") ...DroidDetails @experimental_defer(label: \"b_second\") ...DroidDetails @experimental_defer(label: \"b_third\") @include(if: $cond3) ...DroidDetails @experimental_defer(label: \"b_fourth\") @skip(if: $cond4) } }  fragment DroidDetails on Droid { name }";
+  public static final String OPERATION_DOCUMENT = "query SpreadMultipleWithDeferAndInclude($cond1: Boolean!, $cond2: Boolean!, $cond3: Boolean!, $cond4: Boolean!) { hero { __typename ...DroidDetails @include(if: $cond1) ...DroidDetails @skip(if: $cond2) ...DroidDetails @defer(label: \"b_first\") ...DroidDetails @defer(label: \"b_second\") ...DroidDetails @defer(label: \"b_third\") @include(if: $cond3) ...DroidDetails @defer(label: \"b_fourth\") @skip(if: $cond4) } }  fragment DroidDetails on Droid { name }";
 
   public static final String OPERATION_NAME = "SpreadMultipleWithDeferAndInclude";
 
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferWithIf.java.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferWithIf.java.expected
index c586e04c49..c410e366e3 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferWithIf.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferWithIf.java.expected
@@ -24,7 +24,7 @@ import java.lang.Override;
 import java.lang.String;
 
 public class SpreadMultipleWithDeferWithIf implements Query<SpreadMultipleWithDeferWithIf.Data> {
-  public static final String OPERATION_ID = "f98db9747dd000723759253dacdd7a4e45eaa6003e459c001799901f96abbd8f";
+  public static final String OPERATION_ID = "ecdac17ca37d6cbf3a6e5059904fabfd96193cbe0720eb27880026b518feec9f";
 
   /**
    * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -33,9 +33,9 @@ public class SpreadMultipleWithDeferWithIf implements Query<SpreadMultipleWithDe
    * query SpreadMultipleWithDeferWithIf($cond: Boolean!) {
    *   hero {
    *     __typename
-   *     ...CharacterDetails @experimental_defer(label: "c_first", if: false)
-   *     ...CharacterDetails2 @experimental_defer(label: "c_second", if: true)
-   *     ...CharacterDetails3 @experimental_defer(label: "c_third", if: $cond)
+   *     ...CharacterDetails @defer(label: "c_first", if: false)
+   *     ...CharacterDetails2 @defer(label: "c_second", if: true)
+   *     ...CharacterDetails3 @defer(label: "c_third", if: $cond)
    *   }
    * }
    *
@@ -51,7 +51,7 @@ public class SpreadMultipleWithDeferWithIf implements Query<SpreadMultipleWithDe
    *   birthDate
    * }
    */
-  public static final String OPERATION_DOCUMENT = "query SpreadMultipleWithDeferWithIf($cond: Boolean!) { hero { __typename ...CharacterDetails @experimental_defer(label: \"c_first\", if: false) ...CharacterDetails2 @experimental_defer(label: \"c_second\", if: true) ...CharacterDetails3 @experimental_defer(label: \"c_third\", if: $cond) } }  fragment CharacterDetails on Droid { name }  fragment CharacterDetails2 on Droid { id }  fragment CharacterDetails3 on Droid { birthDate }";
+  public static final String OPERATION_DOCUMENT = "query SpreadMultipleWithDeferWithIf($cond: Boolean!) { hero { __typename ...CharacterDetails @defer(label: \"c_first\", if: false) ...CharacterDetails2 @defer(label: \"c_second\", if: true) ...CharacterDetails3 @defer(label: \"c_third\", if: $cond) } }  fragment CharacterDetails on Droid { name }  fragment CharacterDetails2 on Droid { id }  fragment CharacterDetails3 on Droid { birthDate }";
 
   public static final String OPERATION_NAME = "SpreadMultipleWithDeferWithIf";
 
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/SpreadSingleWithDefer.java.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/SpreadSingleWithDefer.java.expected
index 3ea706b416..eea1e28ee9 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/SpreadSingleWithDefer.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/java/operationBased/fragments_with_defer_and_include_directives/SpreadSingleWithDefer.java.expected
@@ -20,7 +20,7 @@ import java.lang.Override;
 import java.lang.String;
 
 public class SpreadSingleWithDefer implements Query<SpreadSingleWithDefer.Data> {
-  public static final String OPERATION_ID = "d7b739ea7224dce16c1992e5df95207a06f4f92b8231db42098755afac7a6439";
+  public static final String OPERATION_ID = "fad1c3622a6f35d5fa4ad7b5e4a8d50525c350d4688837022f0f7a6f0aed2ba0";
 
   /**
    * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -29,7 +29,7 @@ public class SpreadSingleWithDefer implements Query<SpreadSingleWithDefer.Data>
    * query SpreadSingleWithDefer {
    *   hero {
    *     __typename
-   *     ...DroidDetails @experimental_defer
+   *     ...DroidDetails @defer
    *   }
    * }
    *
@@ -37,7 +37,7 @@ public class SpreadSingleWithDefer implements Query<SpreadSingleWithDefer.Data>
    *   name
    * }
    */
-  public static final String OPERATION_DOCUMENT = "query SpreadSingleWithDefer { hero { __typename ...DroidDetails @experimental_defer } }  fragment DroidDetails on Droid { name }";
+  public static final String OPERATION_DOCUMENT = "query SpreadSingleWithDefer { hero { __typename ...DroidDetails @defer } }  fragment DroidDetails on Droid { name }";
 
   public static final String OPERATION_NAME = "SpreadSingleWithDefer";
 
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/InlineMultipleWithDefer.kt.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/InlineMultipleWithDefer.kt.expected
index b5ce7ac30a..c23f2e080d 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/InlineMultipleWithDefer.kt.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/InlineMultipleWithDefer.kt.expected
@@ -80,7 +80,7 @@ public class InlineMultipleWithDefer() : Query<InlineMultipleWithDefer.Data> {
 
   public companion object {
     public const val OPERATION_ID: String =
-        "9811408b41402ad913abcd7bb5ce221d926a3c545f3f401706b25aefa816081e"
+        "9331f0c719bafb010d29f76c720d4488f45c5196bf3fb8908b2be30bc546e355"
 
     /**
      * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -89,10 +89,10 @@ public class InlineMultipleWithDefer() : Query<InlineMultipleWithDefer.Data> {
      * query InlineMultipleWithDefer {
      *   hero {
      *     __typename
-     *     ... on Droid @experimental_defer(label: "d_first") {
+     *     ... on Droid @defer(label: "d_first") {
      *       name
      *     }
-     *     ... on Droid @experimental_defer(label: "d_second") {
+     *     ... on Droid @defer(label: "d_second") {
      *       id
      *     }
      *   }
@@ -100,7 +100,7 @@ public class InlineMultipleWithDefer() : Query<InlineMultipleWithDefer.Data> {
      */
     public val OPERATION_DOCUMENT: String
       get() =
-          "query InlineMultipleWithDefer { hero { __typename ... on Droid @experimental_defer(label: \"d_first\") { name } ... on Droid @experimental_defer(label: \"d_second\") { id } } }"
+          "query InlineMultipleWithDefer { hero { __typename ... on Droid @defer(label: \"d_first\") { name } ... on Droid @defer(label: \"d_second\") { id } } }"
 
     public const val OPERATION_NAME: String = "InlineMultipleWithDefer"
   }
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/InlineMultipleWithDeferAndInclude.kt.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/InlineMultipleWithDeferAndInclude.kt.expected
index 702207f155..807596fdd6 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/InlineMultipleWithDeferAndInclude.kt.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/InlineMultipleWithDeferAndInclude.kt.expected
@@ -129,7 +129,7 @@ public data class InlineMultipleWithDeferAndInclude(
 
   public companion object {
     public const val OPERATION_ID: String =
-        "90fbc93ce8710e768303863f05c634101ecab0723c10e370c3b8c643ff30f96e"
+        "f159c1ac4f33a49c5c9833e06a2606e2fc7ede812e119909eb45f95dc2aa01fc"
 
     /**
      * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -145,16 +145,16 @@ public data class InlineMultipleWithDeferAndInclude(
      *     ... on Droid @skip(if: $cond2) {
      *       id
      *     }
-     *     ... on Droid @experimental_defer(label: "e_first") {
+     *     ... on Droid @defer(label: "e_first") {
      *       name
      *     }
-     *     ... on Droid @experimental_defer(label: "e_second") {
+     *     ... on Droid @defer(label: "e_second") {
      *       id
      *     }
-     *     ... on Droid @experimental_defer(label: "e_third") @include(if: $cond3) {
+     *     ... on Droid @defer(label: "e_third") @include(if: $cond3) {
      *       name
      *     }
-     *     ... on Droid @experimental_defer(label: "e_fourth") @skip(if: $cond4) {
+     *     ... on Droid @defer(label: "e_fourth") @skip(if: $cond4) {
      *       id
      *     }
      *   }
@@ -162,7 +162,7 @@ public data class InlineMultipleWithDeferAndInclude(
      */
     public val OPERATION_DOCUMENT: String
       get() =
-          "query InlineMultipleWithDeferAndInclude(${'$'}cond1: Boolean!, ${'$'}cond2: Boolean!, ${'$'}cond3: Boolean!, ${'$'}cond4: Boolean!) { hero { __typename ... on Droid @include(if: ${'$'}cond1) { name } ... on Droid @skip(if: ${'$'}cond2) { id } ... on Droid @experimental_defer(label: \"e_first\") { name } ... on Droid @experimental_defer(label: \"e_second\") { id } ... on Droid @experimental_defer(label: \"e_third\") @include(if: ${'$'}cond3) { name } ... on Droid @experimental_defer(label: \"e_fourth\") @skip(if: ${'$'}cond4) { id } } }"
+          "query InlineMultipleWithDeferAndInclude(${'$'}cond1: Boolean!, ${'$'}cond2: Boolean!, ${'$'}cond3: Boolean!, ${'$'}cond4: Boolean!) { hero { __typename ... on Droid @include(if: ${'$'}cond1) { name } ... on Droid @skip(if: ${'$'}cond2) { id } ... on Droid @defer(label: \"e_first\") { name } ... on Droid @defer(label: \"e_second\") { id } ... on Droid @defer(label: \"e_third\") @include(if: ${'$'}cond3) { name } ... on Droid @defer(label: \"e_fourth\") @skip(if: ${'$'}cond4) { id } } }"
 
     public const val OPERATION_NAME: String = "InlineMultipleWithDeferAndInclude"
   }
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/InlineMultipleWithDeferWithIf.kt.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/InlineMultipleWithDeferWithIf.kt.expected
index 1b31cfb3cc..5d1f92f138 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/InlineMultipleWithDeferWithIf.kt.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/InlineMultipleWithDeferWithIf.kt.expected
@@ -90,7 +90,7 @@ public data class InlineMultipleWithDeferWithIf(
 
   public companion object {
     public const val OPERATION_ID: String =
-        "3e777ab8534ca2847df43e92a828787127e9536d7c1ab8136985620443c2b991"
+        "9dc79c78df7375c3d860d16df3ea839ea45c7f8420976f63414610d338f0caf1"
 
     /**
      * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -99,13 +99,13 @@ public data class InlineMultipleWithDeferWithIf(
      * query InlineMultipleWithDeferWithIf($cond: Boolean!) {
      *   hero {
      *     __typename
-     *     ... on Character @experimental_defer(label: "f_first", if: false) {
+     *     ... on Character @defer(label: "f_first", if: false) {
      *       id
      *     }
-     *     ... on Character @experimental_defer(label: "f_second", if: true) {
+     *     ... on Character @defer(label: "f_second", if: true) {
      *       name
      *     }
-     *     ... on Character @experimental_defer(label: "f_third", if: $cond) {
+     *     ... on Character @defer(label: "f_third", if: $cond) {
      *       name
      *     }
      *   }
@@ -113,7 +113,7 @@ public data class InlineMultipleWithDeferWithIf(
      */
     public val OPERATION_DOCUMENT: String
       get() =
-          "query InlineMultipleWithDeferWithIf(${'$'}cond: Boolean!) { hero { __typename ... on Character @experimental_defer(label: \"f_first\", if: false) { id } ... on Character @experimental_defer(label: \"f_second\", if: true) { name } ... on Character @experimental_defer(label: \"f_third\", if: ${'$'}cond) { name } } }"
+          "query InlineMultipleWithDeferWithIf(${'$'}cond: Boolean!) { hero { __typename ... on Character @defer(label: \"f_first\", if: false) { id } ... on Character @defer(label: \"f_second\", if: true) { name } ... on Character @defer(label: \"f_third\", if: ${'$'}cond) { name } } }"
 
     public const val OPERATION_NAME: String = "InlineMultipleWithDeferWithIf"
   }
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/InlineSingleWithDefer.kt.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/InlineSingleWithDefer.kt.expected
index 4e0966cec0..ee6cc409d8 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/InlineSingleWithDefer.kt.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/InlineSingleWithDefer.kt.expected
@@ -68,7 +68,7 @@ public class InlineSingleWithDefer() : Query<InlineSingleWithDefer.Data> {
 
   public companion object {
     public const val OPERATION_ID: String =
-        "da1ea6b7b54f4bc6e0754b9bbe45a002500fef00de7f3605a4efd02133c20def"
+        "70222802c9192f810f19a54d31e039ce0fc3b8baac231841f0a0e8b4200c312b"
 
     /**
      * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -77,15 +77,14 @@ public class InlineSingleWithDefer() : Query<InlineSingleWithDefer.Data> {
      * query InlineSingleWithDefer {
      *   hero {
      *     __typename
-     *     ... on Droid @experimental_defer {
+     *     ... on Droid @defer {
      *       name
      *     }
      *   }
      * }
      */
     public val OPERATION_DOCUMENT: String
-      get() =
-          "query InlineSingleWithDefer { hero { __typename ... on Droid @experimental_defer { name } } }"
+      get() = "query InlineSingleWithDefer { hero { __typename ... on Droid @defer { name } } }"
 
     public const val OPERATION_NAME: String = "InlineSingleWithDefer"
   }
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/SpreadMultipleWithDefer.kt.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/SpreadMultipleWithDefer.kt.expected
index 7bb3959f27..f0dd40c860 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/SpreadMultipleWithDefer.kt.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/SpreadMultipleWithDefer.kt.expected
@@ -68,7 +68,7 @@ public class SpreadMultipleWithDefer() : Query<SpreadMultipleWithDefer.Data> {
 
   public companion object {
     public const val OPERATION_ID: String =
-        "e52d7b5c6a99f54c7d8e7f1d6c4f6e604586b4c83b212436661068e98f4f7ad1"
+        "7cd4d1b6a14f96cff4bbbdbd3b3ab1aa365ffc65e1515ff6e22935010543ad71"
 
     /**
      * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -77,8 +77,8 @@ public class SpreadMultipleWithDefer() : Query<SpreadMultipleWithDefer.Data> {
      * query SpreadMultipleWithDefer {
      *   hero {
      *     __typename
-     *     ...DroidDetails @experimental_defer(label: "a_first")
-     *     ...DroidDetails @experimental_defer(label: "a_second")
+     *     ...DroidDetails @defer(label: "a_first")
+     *     ...DroidDetails @defer(label: "a_second")
      *   }
      * }
      *
@@ -88,7 +88,7 @@ public class SpreadMultipleWithDefer() : Query<SpreadMultipleWithDefer.Data> {
      */
     public val OPERATION_DOCUMENT: String
       get() =
-          "query SpreadMultipleWithDefer { hero { __typename ...DroidDetails @experimental_defer(label: \"a_first\") ...DroidDetails @experimental_defer(label: \"a_second\") } }  fragment DroidDetails on Droid { name }"
+          "query SpreadMultipleWithDefer { hero { __typename ...DroidDetails @defer(label: \"a_first\") ...DroidDetails @defer(label: \"a_second\") } }  fragment DroidDetails on Droid { name }"
 
     public const val OPERATION_NAME: String = "SpreadMultipleWithDefer"
   }
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferAndInclude.kt.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferAndInclude.kt.expected
index eb5458fe38..82b7e7013d 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferAndInclude.kt.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferAndInclude.kt.expected
@@ -69,7 +69,7 @@ public data class SpreadMultipleWithDeferAndInclude(
 
   public companion object {
     public const val OPERATION_ID: String =
-        "de31db86e7b05f57e3d3d700a4811e4aba6c56860dc18f94879165a5e04fcfe8"
+        "1c9d61b4af65df2bfed92353244efbb66d20a35daf747507e66ed9d20dcd1517"
 
     /**
      * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -81,10 +81,10 @@ public data class SpreadMultipleWithDeferAndInclude(
      *     __typename
      *     ...DroidDetails @include(if: $cond1)
      *     ...DroidDetails @skip(if: $cond2)
-     *     ...DroidDetails @experimental_defer(label: "b_first")
-     *     ...DroidDetails @experimental_defer(label: "b_second")
-     *     ...DroidDetails @experimental_defer(label: "b_third") @include(if: $cond3)
-     *     ...DroidDetails @experimental_defer(label: "b_fourth") @skip(if: $cond4)
+     *     ...DroidDetails @defer(label: "b_first")
+     *     ...DroidDetails @defer(label: "b_second")
+     *     ...DroidDetails @defer(label: "b_third") @include(if: $cond3)
+     *     ...DroidDetails @defer(label: "b_fourth") @skip(if: $cond4)
      *   }
      * }
      *
@@ -94,7 +94,7 @@ public data class SpreadMultipleWithDeferAndInclude(
      */
     public val OPERATION_DOCUMENT: String
       get() =
-          "query SpreadMultipleWithDeferAndInclude(${'$'}cond1: Boolean!, ${'$'}cond2: Boolean!, ${'$'}cond3: Boolean!, ${'$'}cond4: Boolean!) { hero { __typename ...DroidDetails @include(if: ${'$'}cond1) ...DroidDetails @skip(if: ${'$'}cond2) ...DroidDetails @experimental_defer(label: \"b_first\") ...DroidDetails @experimental_defer(label: \"b_second\") ...DroidDetails @experimental_defer(label: \"b_third\") @include(if: ${'$'}cond3) ...DroidDetails @experimental_defer(label: \"b_fourth\") @skip(if: ${'$'}cond4) } }  fragment DroidDetails on Droid { name }"
+          "query SpreadMultipleWithDeferAndInclude(${'$'}cond1: Boolean!, ${'$'}cond2: Boolean!, ${'$'}cond3: Boolean!, ${'$'}cond4: Boolean!) { hero { __typename ...DroidDetails @include(if: ${'$'}cond1) ...DroidDetails @skip(if: ${'$'}cond2) ...DroidDetails @defer(label: \"b_first\") ...DroidDetails @defer(label: \"b_second\") ...DroidDetails @defer(label: \"b_third\") @include(if: ${'$'}cond3) ...DroidDetails @defer(label: \"b_fourth\") @skip(if: ${'$'}cond4) } }  fragment DroidDetails on Droid { name }"
 
     public const val OPERATION_NAME: String = "SpreadMultipleWithDeferAndInclude"
   }
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferWithIf.kt.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferWithIf.kt.expected
index 4a6a975feb..f2c6518b68 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferWithIf.kt.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferWithIf.kt.expected
@@ -76,7 +76,7 @@ public data class SpreadMultipleWithDeferWithIf(
 
   public companion object {
     public const val OPERATION_ID: String =
-        "f98db9747dd000723759253dacdd7a4e45eaa6003e459c001799901f96abbd8f"
+        "ecdac17ca37d6cbf3a6e5059904fabfd96193cbe0720eb27880026b518feec9f"
 
     /**
      * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -85,9 +85,9 @@ public data class SpreadMultipleWithDeferWithIf(
      * query SpreadMultipleWithDeferWithIf($cond: Boolean!) {
      *   hero {
      *     __typename
-     *     ...CharacterDetails @experimental_defer(label: "c_first", if: false)
-     *     ...CharacterDetails2 @experimental_defer(label: "c_second", if: true)
-     *     ...CharacterDetails3 @experimental_defer(label: "c_third", if: $cond)
+     *     ...CharacterDetails @defer(label: "c_first", if: false)
+     *     ...CharacterDetails2 @defer(label: "c_second", if: true)
+     *     ...CharacterDetails3 @defer(label: "c_third", if: $cond)
      *   }
      * }
      *
@@ -105,7 +105,7 @@ public data class SpreadMultipleWithDeferWithIf(
      */
     public val OPERATION_DOCUMENT: String
       get() =
-          "query SpreadMultipleWithDeferWithIf(${'$'}cond: Boolean!) { hero { __typename ...CharacterDetails @experimental_defer(label: \"c_first\", if: false) ...CharacterDetails2 @experimental_defer(label: \"c_second\", if: true) ...CharacterDetails3 @experimental_defer(label: \"c_third\", if: ${'$'}cond) } }  fragment CharacterDetails on Droid { name }  fragment CharacterDetails2 on Droid { id }  fragment CharacterDetails3 on Droid { birthDate }"
+          "query SpreadMultipleWithDeferWithIf(${'$'}cond: Boolean!) { hero { __typename ...CharacterDetails @defer(label: \"c_first\", if: false) ...CharacterDetails2 @defer(label: \"c_second\", if: true) ...CharacterDetails3 @defer(label: \"c_third\", if: ${'$'}cond) } }  fragment CharacterDetails on Droid { name }  fragment CharacterDetails2 on Droid { id }  fragment CharacterDetails3 on Droid { birthDate }"
 
     public const val OPERATION_NAME: String = "SpreadMultipleWithDeferWithIf"
   }
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/SpreadSingleWithDefer.kt.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/SpreadSingleWithDefer.kt.expected
index f1fce89d17..ec94193440 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/SpreadSingleWithDefer.kt.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/compat/fragments_with_defer_and_include_directives/SpreadSingleWithDefer.kt.expected
@@ -68,7 +68,7 @@ public class SpreadSingleWithDefer() : Query<SpreadSingleWithDefer.Data> {
 
   public companion object {
     public const val OPERATION_ID: String =
-        "d7b739ea7224dce16c1992e5df95207a06f4f92b8231db42098755afac7a6439"
+        "fad1c3622a6f35d5fa4ad7b5e4a8d50525c350d4688837022f0f7a6f0aed2ba0"
 
     /**
      * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -77,7 +77,7 @@ public class SpreadSingleWithDefer() : Query<SpreadSingleWithDefer.Data> {
      * query SpreadSingleWithDefer {
      *   hero {
      *     __typename
-     *     ...DroidDetails @experimental_defer
+     *     ...DroidDetails @defer
      *   }
      * }
      *
@@ -87,7 +87,7 @@ public class SpreadSingleWithDefer() : Query<SpreadSingleWithDefer.Data> {
      */
     public val OPERATION_DOCUMENT: String
       get() =
-          "query SpreadSingleWithDefer { hero { __typename ...DroidDetails @experimental_defer } }  fragment DroidDetails on Droid { name }"
+          "query SpreadSingleWithDefer { hero { __typename ...DroidDetails @defer } }  fragment DroidDetails on Droid { name }"
 
     public const val OPERATION_NAME: String = "SpreadSingleWithDefer"
   }
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDefer.kt.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDefer.kt.expected
index c2e2ab7d64..d845c8beeb 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDefer.kt.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDefer.kt.expected
@@ -78,7 +78,7 @@ public class InlineMultipleWithDefer() : Query<InlineMultipleWithDefer.Data> {
 
   public companion object {
     public const val OPERATION_ID: String =
-        "9811408b41402ad913abcd7bb5ce221d926a3c545f3f401706b25aefa816081e"
+        "9331f0c719bafb010d29f76c720d4488f45c5196bf3fb8908b2be30bc546e355"
 
     /**
      * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -87,10 +87,10 @@ public class InlineMultipleWithDefer() : Query<InlineMultipleWithDefer.Data> {
      * query InlineMultipleWithDefer {
      *   hero {
      *     __typename
-     *     ... on Droid @experimental_defer(label: "d_first") {
+     *     ... on Droid @defer(label: "d_first") {
      *       name
      *     }
-     *     ... on Droid @experimental_defer(label: "d_second") {
+     *     ... on Droid @defer(label: "d_second") {
      *       id
      *     }
      *   }
@@ -98,7 +98,7 @@ public class InlineMultipleWithDefer() : Query<InlineMultipleWithDefer.Data> {
      */
     public val OPERATION_DOCUMENT: String
       get() =
-          "query InlineMultipleWithDefer { hero { __typename ... on Droid @experimental_defer(label: \"d_first\") { name } ... on Droid @experimental_defer(label: \"d_second\") { id } } }"
+          "query InlineMultipleWithDefer { hero { __typename ... on Droid @defer(label: \"d_first\") { name } ... on Droid @defer(label: \"d_second\") { id } } }"
 
     public const val OPERATION_NAME: String = "InlineMultipleWithDefer"
   }
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDeferAndInclude.kt.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDeferAndInclude.kt.expected
index 4ec8b3b3a5..3f57610116 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDeferAndInclude.kt.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDeferAndInclude.kt.expected
@@ -123,7 +123,7 @@ public data class InlineMultipleWithDeferAndInclude(
 
   public companion object {
     public const val OPERATION_ID: String =
-        "90fbc93ce8710e768303863f05c634101ecab0723c10e370c3b8c643ff30f96e"
+        "f159c1ac4f33a49c5c9833e06a2606e2fc7ede812e119909eb45f95dc2aa01fc"
 
     /**
      * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -139,16 +139,16 @@ public data class InlineMultipleWithDeferAndInclude(
      *     ... on Droid @skip(if: $cond2) {
      *       id
      *     }
-     *     ... on Droid @experimental_defer(label: "e_first") {
+     *     ... on Droid @defer(label: "e_first") {
      *       name
      *     }
-     *     ... on Droid @experimental_defer(label: "e_second") {
+     *     ... on Droid @defer(label: "e_second") {
      *       id
      *     }
-     *     ... on Droid @experimental_defer(label: "e_third") @include(if: $cond3) {
+     *     ... on Droid @defer(label: "e_third") @include(if: $cond3) {
      *       name
      *     }
-     *     ... on Droid @experimental_defer(label: "e_fourth") @skip(if: $cond4) {
+     *     ... on Droid @defer(label: "e_fourth") @skip(if: $cond4) {
      *       id
      *     }
      *   }
@@ -156,7 +156,7 @@ public data class InlineMultipleWithDeferAndInclude(
      */
     public val OPERATION_DOCUMENT: String
       get() =
-          "query InlineMultipleWithDeferAndInclude(${'$'}cond1: Boolean!, ${'$'}cond2: Boolean!, ${'$'}cond3: Boolean!, ${'$'}cond4: Boolean!) { hero { __typename ... on Droid @include(if: ${'$'}cond1) { name } ... on Droid @skip(if: ${'$'}cond2) { id } ... on Droid @experimental_defer(label: \"e_first\") { name } ... on Droid @experimental_defer(label: \"e_second\") { id } ... on Droid @experimental_defer(label: \"e_third\") @include(if: ${'$'}cond3) { name } ... on Droid @experimental_defer(label: \"e_fourth\") @skip(if: ${'$'}cond4) { id } } }"
+          "query InlineMultipleWithDeferAndInclude(${'$'}cond1: Boolean!, ${'$'}cond2: Boolean!, ${'$'}cond3: Boolean!, ${'$'}cond4: Boolean!) { hero { __typename ... on Droid @include(if: ${'$'}cond1) { name } ... on Droid @skip(if: ${'$'}cond2) { id } ... on Droid @defer(label: \"e_first\") { name } ... on Droid @defer(label: \"e_second\") { id } ... on Droid @defer(label: \"e_third\") @include(if: ${'$'}cond3) { name } ... on Droid @defer(label: \"e_fourth\") @skip(if: ${'$'}cond4) { id } } }"
 
     public const val OPERATION_NAME: String = "InlineMultipleWithDeferAndInclude"
   }
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDeferWithIf.kt.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDeferWithIf.kt.expected
index 1d6012561a..9acd69c4a7 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDeferWithIf.kt.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/InlineMultipleWithDeferWithIf.kt.expected
@@ -87,7 +87,7 @@ public data class InlineMultipleWithDeferWithIf(
 
   public companion object {
     public const val OPERATION_ID: String =
-        "3e777ab8534ca2847df43e92a828787127e9536d7c1ab8136985620443c2b991"
+        "9dc79c78df7375c3d860d16df3ea839ea45c7f8420976f63414610d338f0caf1"
 
     /**
      * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -96,13 +96,13 @@ public data class InlineMultipleWithDeferWithIf(
      * query InlineMultipleWithDeferWithIf($cond: Boolean!) {
      *   hero {
      *     __typename
-     *     ... on Character @experimental_defer(label: "f_first", if: false) {
+     *     ... on Character @defer(label: "f_first", if: false) {
      *       id
      *     }
-     *     ... on Character @experimental_defer(label: "f_second", if: true) {
+     *     ... on Character @defer(label: "f_second", if: true) {
      *       name
      *     }
-     *     ... on Character @experimental_defer(label: "f_third", if: $cond) {
+     *     ... on Character @defer(label: "f_third", if: $cond) {
      *       name
      *     }
      *   }
@@ -110,7 +110,7 @@ public data class InlineMultipleWithDeferWithIf(
      */
     public val OPERATION_DOCUMENT: String
       get() =
-          "query InlineMultipleWithDeferWithIf(${'$'}cond: Boolean!) { hero { __typename ... on Character @experimental_defer(label: \"f_first\", if: false) { id } ... on Character @experimental_defer(label: \"f_second\", if: true) { name } ... on Character @experimental_defer(label: \"f_third\", if: ${'$'}cond) { name } } }"
+          "query InlineMultipleWithDeferWithIf(${'$'}cond: Boolean!) { hero { __typename ... on Character @defer(label: \"f_first\", if: false) { id } ... on Character @defer(label: \"f_second\", if: true) { name } ... on Character @defer(label: \"f_third\", if: ${'$'}cond) { name } } }"
 
     public const val OPERATION_NAME: String = "InlineMultipleWithDeferWithIf"
   }
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/InlineSingleWithDefer.kt.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/InlineSingleWithDefer.kt.expected
index ee0e6530cf..e47c40d32f 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/InlineSingleWithDefer.kt.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/InlineSingleWithDefer.kt.expected
@@ -67,7 +67,7 @@ public class InlineSingleWithDefer() : Query<InlineSingleWithDefer.Data> {
 
   public companion object {
     public const val OPERATION_ID: String =
-        "da1ea6b7b54f4bc6e0754b9bbe45a002500fef00de7f3605a4efd02133c20def"
+        "70222802c9192f810f19a54d31e039ce0fc3b8baac231841f0a0e8b4200c312b"
 
     /**
      * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -76,15 +76,14 @@ public class InlineSingleWithDefer() : Query<InlineSingleWithDefer.Data> {
      * query InlineSingleWithDefer {
      *   hero {
      *     __typename
-     *     ... on Droid @experimental_defer {
+     *     ... on Droid @defer {
      *       name
      *     }
      *   }
      * }
      */
     public val OPERATION_DOCUMENT: String
-      get() =
-          "query InlineSingleWithDefer { hero { __typename ... on Droid @experimental_defer { name } } }"
+      get() = "query InlineSingleWithDefer { hero { __typename ... on Droid @defer { name } } }"
 
     public const val OPERATION_NAME: String = "InlineSingleWithDefer"
   }
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDefer.kt.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDefer.kt.expected
index cb61f5460e..80ba3e6853 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDefer.kt.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDefer.kt.expected
@@ -61,7 +61,7 @@ public class SpreadMultipleWithDefer() : Query<SpreadMultipleWithDefer.Data> {
 
   public companion object {
     public const val OPERATION_ID: String =
-        "e52d7b5c6a99f54c7d8e7f1d6c4f6e604586b4c83b212436661068e98f4f7ad1"
+        "7cd4d1b6a14f96cff4bbbdbd3b3ab1aa365ffc65e1515ff6e22935010543ad71"
 
     /**
      * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -70,8 +70,8 @@ public class SpreadMultipleWithDefer() : Query<SpreadMultipleWithDefer.Data> {
      * query SpreadMultipleWithDefer {
      *   hero {
      *     __typename
-     *     ...DroidDetails @experimental_defer(label: "a_first")
-     *     ...DroidDetails @experimental_defer(label: "a_second")
+     *     ...DroidDetails @defer(label: "a_first")
+     *     ...DroidDetails @defer(label: "a_second")
      *   }
      * }
      *
@@ -81,7 +81,7 @@ public class SpreadMultipleWithDefer() : Query<SpreadMultipleWithDefer.Data> {
      */
     public val OPERATION_DOCUMENT: String
       get() =
-          "query SpreadMultipleWithDefer { hero { __typename ...DroidDetails @experimental_defer(label: \"a_first\") ...DroidDetails @experimental_defer(label: \"a_second\") } }  fragment DroidDetails on Droid { name }"
+          "query SpreadMultipleWithDefer { hero { __typename ...DroidDetails @defer(label: \"a_first\") ...DroidDetails @defer(label: \"a_second\") } }  fragment DroidDetails on Droid { name }"
 
     public const val OPERATION_NAME: String = "SpreadMultipleWithDefer"
   }
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferAndInclude.kt.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferAndInclude.kt.expected
index 7e23cf33c9..a83d2a9dac 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferAndInclude.kt.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferAndInclude.kt.expected
@@ -62,7 +62,7 @@ public data class SpreadMultipleWithDeferAndInclude(
 
   public companion object {
     public const val OPERATION_ID: String =
-        "de31db86e7b05f57e3d3d700a4811e4aba6c56860dc18f94879165a5e04fcfe8"
+        "1c9d61b4af65df2bfed92353244efbb66d20a35daf747507e66ed9d20dcd1517"
 
     /**
      * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -74,10 +74,10 @@ public data class SpreadMultipleWithDeferAndInclude(
      *     __typename
      *     ...DroidDetails @include(if: $cond1)
      *     ...DroidDetails @skip(if: $cond2)
-     *     ...DroidDetails @experimental_defer(label: "b_first")
-     *     ...DroidDetails @experimental_defer(label: "b_second")
-     *     ...DroidDetails @experimental_defer(label: "b_third") @include(if: $cond3)
-     *     ...DroidDetails @experimental_defer(label: "b_fourth") @skip(if: $cond4)
+     *     ...DroidDetails @defer(label: "b_first")
+     *     ...DroidDetails @defer(label: "b_second")
+     *     ...DroidDetails @defer(label: "b_third") @include(if: $cond3)
+     *     ...DroidDetails @defer(label: "b_fourth") @skip(if: $cond4)
      *   }
      * }
      *
@@ -87,7 +87,7 @@ public data class SpreadMultipleWithDeferAndInclude(
      */
     public val OPERATION_DOCUMENT: String
       get() =
-          "query SpreadMultipleWithDeferAndInclude(${'$'}cond1: Boolean!, ${'$'}cond2: Boolean!, ${'$'}cond3: Boolean!, ${'$'}cond4: Boolean!) { hero { __typename ...DroidDetails @include(if: ${'$'}cond1) ...DroidDetails @skip(if: ${'$'}cond2) ...DroidDetails @experimental_defer(label: \"b_first\") ...DroidDetails @experimental_defer(label: \"b_second\") ...DroidDetails @experimental_defer(label: \"b_third\") @include(if: ${'$'}cond3) ...DroidDetails @experimental_defer(label: \"b_fourth\") @skip(if: ${'$'}cond4) } }  fragment DroidDetails on Droid { name }"
+          "query SpreadMultipleWithDeferAndInclude(${'$'}cond1: Boolean!, ${'$'}cond2: Boolean!, ${'$'}cond3: Boolean!, ${'$'}cond4: Boolean!) { hero { __typename ...DroidDetails @include(if: ${'$'}cond1) ...DroidDetails @skip(if: ${'$'}cond2) ...DroidDetails @defer(label: \"b_first\") ...DroidDetails @defer(label: \"b_second\") ...DroidDetails @defer(label: \"b_third\") @include(if: ${'$'}cond3) ...DroidDetails @defer(label: \"b_fourth\") @skip(if: ${'$'}cond4) } }  fragment DroidDetails on Droid { name }"
 
     public const val OPERATION_NAME: String = "SpreadMultipleWithDeferAndInclude"
   }
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferWithIf.kt.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferWithIf.kt.expected
index 36c8a748eb..96791e8f4f 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferWithIf.kt.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/SpreadMultipleWithDeferWithIf.kt.expected
@@ -69,7 +69,7 @@ public data class SpreadMultipleWithDeferWithIf(
 
   public companion object {
     public const val OPERATION_ID: String =
-        "f98db9747dd000723759253dacdd7a4e45eaa6003e459c001799901f96abbd8f"
+        "ecdac17ca37d6cbf3a6e5059904fabfd96193cbe0720eb27880026b518feec9f"
 
     /**
      * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -78,9 +78,9 @@ public data class SpreadMultipleWithDeferWithIf(
      * query SpreadMultipleWithDeferWithIf($cond: Boolean!) {
      *   hero {
      *     __typename
-     *     ...CharacterDetails @experimental_defer(label: "c_first", if: false)
-     *     ...CharacterDetails2 @experimental_defer(label: "c_second", if: true)
-     *     ...CharacterDetails3 @experimental_defer(label: "c_third", if: $cond)
+     *     ...CharacterDetails @defer(label: "c_first", if: false)
+     *     ...CharacterDetails2 @defer(label: "c_second", if: true)
+     *     ...CharacterDetails3 @defer(label: "c_third", if: $cond)
      *   }
      * }
      *
@@ -98,7 +98,7 @@ public data class SpreadMultipleWithDeferWithIf(
      */
     public val OPERATION_DOCUMENT: String
       get() =
-          "query SpreadMultipleWithDeferWithIf(${'$'}cond: Boolean!) { hero { __typename ...CharacterDetails @experimental_defer(label: \"c_first\", if: false) ...CharacterDetails2 @experimental_defer(label: \"c_second\", if: true) ...CharacterDetails3 @experimental_defer(label: \"c_third\", if: ${'$'}cond) } }  fragment CharacterDetails on Droid { name }  fragment CharacterDetails2 on Droid { id }  fragment CharacterDetails3 on Droid { birthDate }"
+          "query SpreadMultipleWithDeferWithIf(${'$'}cond: Boolean!) { hero { __typename ...CharacterDetails @defer(label: \"c_first\", if: false) ...CharacterDetails2 @defer(label: \"c_second\", if: true) ...CharacterDetails3 @defer(label: \"c_third\", if: ${'$'}cond) } }  fragment CharacterDetails on Droid { name }  fragment CharacterDetails2 on Droid { id }  fragment CharacterDetails3 on Droid { birthDate }"
 
     public const val OPERATION_NAME: String = "SpreadMultipleWithDeferWithIf"
   }
diff --git a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/SpreadSingleWithDefer.kt.expected b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/SpreadSingleWithDefer.kt.expected
index 7599625ee0..8e18f4b914 100644
--- a/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/SpreadSingleWithDefer.kt.expected
+++ b/apollo-compiler/src/test/graphql/com/example/fragments_with_defer_and_include_directives/kotlin/operationBased/fragments_with_defer_and_include_directives/SpreadSingleWithDefer.kt.expected
@@ -61,7 +61,7 @@ public class SpreadSingleWithDefer() : Query<SpreadSingleWithDefer.Data> {
 
   public companion object {
     public const val OPERATION_ID: String =
-        "d7b739ea7224dce16c1992e5df95207a06f4f92b8231db42098755afac7a6439"
+        "fad1c3622a6f35d5fa4ad7b5e4a8d50525c350d4688837022f0f7a6f0aed2ba0"
 
     /**
      * The minimized GraphQL document being sent to the server to save a few bytes.
@@ -70,7 +70,7 @@ public class SpreadSingleWithDefer() : Query<SpreadSingleWithDefer.Data> {
      * query SpreadSingleWithDefer {
      *   hero {
      *     __typename
-     *     ...DroidDetails @experimental_defer
+     *     ...DroidDetails @defer
      *   }
      * }
      *
@@ -80,7 +80,7 @@ public class SpreadSingleWithDefer() : Query<SpreadSingleWithDefer.Data> {
      */
     public val OPERATION_DOCUMENT: String
       get() =
-          "query SpreadSingleWithDefer { hero { __typename ...DroidDetails @experimental_defer } }  fragment DroidDetails on Droid { name }"
+          "query SpreadSingleWithDefer { hero { __typename ...DroidDetails @defer } }  fragment DroidDetails on Droid { name }"
 
     public const val OPERATION_NAME: String = "SpreadSingleWithDefer"
   }
diff --git a/apollo-compiler/src/test/graphql/com/example/hero_details/java/operationBased/hero_details/type/hero_type.java.expected b/apollo-compiler/src/test/graphql/com/example/hero_details/java/operationBased/hero_details/type/hero_type.java.expected
index 195b24ae33..731aa6d12c 100644
--- a/apollo-compiler/src/test/graphql/com/example/hero_details/java/operationBased/hero_details/type/hero_type.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/hero_details/java/operationBased/hero_details/type/hero_type.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * Lower case enum type name
  */
 public class hero_type {
-  public static EnumType type = new EnumType("hero_type");
+  public static EnumType type = new EnumType("hero_type", Arrays.asList("human", "droid"));
 
   public static hero_type human = new hero_type("human");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/hero_name_query_long_name/java/operationBased/hero_name_query_long_name/type/Episode.java.expected b/apollo-compiler/src/test/graphql/com/example/hero_name_query_long_name/java/operationBased/hero_name_query_long_name/type/Episode.java.expected
index 65a9848edb..8e4cbf0c81 100644
--- a/apollo-compiler/src/test/graphql/com/example/hero_name_query_long_name/java/operationBased/hero_name_query_long_name/type/Episode.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/hero_name_query_long_name/java/operationBased/hero_name_query_long_name/type/Episode.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * The episodes in the Star Wars trilogy
  */
 public class Episode {
-  public static EnumType type = new EnumType("Episode");
+  public static EnumType type = new EnumType("Episode", Arrays.asList("NEWHOPE", "EMPIRE", "JEDI", "DEPRECATED", "new"));
 
   public static Episode NEWHOPE = new Episode("NEWHOPE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/hero_with_review/java/operationBased/hero_with_review/type/Episode.java.expected b/apollo-compiler/src/test/graphql/com/example/hero_with_review/java/operationBased/hero_with_review/type/Episode.java.expected
index d84b71da2c..cc3bc17252 100644
--- a/apollo-compiler/src/test/graphql/com/example/hero_with_review/java/operationBased/hero_with_review/type/Episode.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/hero_with_review/java/operationBased/hero_with_review/type/Episode.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * The episodes in the Star Wars trilogy
  */
 public class Episode {
-  public static EnumType type = new EnumType("Episode");
+  public static EnumType type = new EnumType("Episode", Arrays.asList("NEWHOPE", "EMPIRE", "JEDI", "DEPRECATED", "new"));
 
   public static Episode NEWHOPE = new Episode("NEWHOPE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/inline_fragment_intersection/java/operationBased/inline_fragment_intersection/type/Race.java.expected b/apollo-compiler/src/test/graphql/com/example/inline_fragment_intersection/java/operationBased/inline_fragment_intersection/type/Race.java.expected
index c35b9e69c7..c72cd815d3 100644
--- a/apollo-compiler/src/test/graphql/com/example/inline_fragment_intersection/java/operationBased/inline_fragment_intersection/type/Race.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/inline_fragment_intersection/java/operationBased/inline_fragment_intersection/type/Race.java.expected
@@ -9,9 +9,10 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 public class Race {
-  public static EnumType type = new EnumType("Race");
+  public static EnumType type = new EnumType("Race", Arrays.asList("WOOKIE", "GUMGAN", "EWOK"));
 
   public static Race WOOKIE = new Race("WOOKIE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/inline_fragments_with_friends/java/operationBased/inline_fragments_with_friends/type/Episode.java.expected b/apollo-compiler/src/test/graphql/com/example/inline_fragments_with_friends/java/operationBased/inline_fragments_with_friends/type/Episode.java.expected
index 045191fe07..138897dd51 100644
--- a/apollo-compiler/src/test/graphql/com/example/inline_fragments_with_friends/java/operationBased/inline_fragments_with_friends/type/Episode.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/inline_fragments_with_friends/java/operationBased/inline_fragments_with_friends/type/Episode.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * The episodes in the Star Wars trilogy
  */
 public class Episode {
-  public static EnumType type = new EnumType("Episode");
+  public static EnumType type = new EnumType("Episode", Arrays.asList("NEWHOPE", "EMPIRE", "JEDI", "DEPRECATED", "new"));
 
   public static Episode NEWHOPE = new Episode("NEWHOPE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/input_object_type/java/operationBased/input_object_type/type/Episode.java.expected b/apollo-compiler/src/test/graphql/com/example/input_object_type/java/operationBased/input_object_type/type/Episode.java.expected
index fbd8491439..c40ee5ac4b 100644
--- a/apollo-compiler/src/test/graphql/com/example/input_object_type/java/operationBased/input_object_type/type/Episode.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/input_object_type/java/operationBased/input_object_type/type/Episode.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * The episodes in the Star Wars trilogy
  */
 public class Episode {
-  public static EnumType type = new EnumType("Episode");
+  public static EnumType type = new EnumType("Episode", Arrays.asList("NEWHOPE", "EMPIRE", "JEDI", "DEPRECATED", "new"));
 
   public static Episode NEWHOPE = new Episode("NEWHOPE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/input_object_variable_and_argument/java/operationBased/input_object_variable_and_argument/type/Episode.java.expected b/apollo-compiler/src/test/graphql/com/example/input_object_variable_and_argument/java/operationBased/input_object_variable_and_argument/type/Episode.java.expected
index 40dbf55414..809fd4ea0a 100644
--- a/apollo-compiler/src/test/graphql/com/example/input_object_variable_and_argument/java/operationBased/input_object_variable_and_argument/type/Episode.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/input_object_variable_and_argument/java/operationBased/input_object_variable_and_argument/type/Episode.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * The episodes in the Star Wars trilogy
  */
 public class Episode {
-  public static EnumType type = new EnumType("Episode");
+  public static EnumType type = new EnumType("Episode", Arrays.asList("NEWHOPE", "EMPIRE", "JEDI", "DEPRECATED", "new"));
 
   public static Episode NEWHOPE = new Episode("NEWHOPE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/measurements b/apollo-compiler/src/test/graphql/com/example/measurements
index e85c7e4a4e..712cba10c3 100644
--- a/apollo-compiler/src/test/graphql/com/example/measurements
+++ b/apollo-compiler/src/test/graphql/com/example/measurements
@@ -2,37 +2,37 @@
 // If you updated the codegen and test fixtures, you should commit this file too.
 
 Test:                                                                                      Total LOC:
-aggregate-all                                                                                  194954
+aggregate-all                                                                                  194981
 aggregate-kotlin-responseBased                                                                  50287
 aggregate-kotlin-operationBased                                                                 35446
 aggregate-kotlin-compat                                                                         36831
-aggregate-java-operationBased                                                                   72390
+aggregate-java-operationBased                                                                   72417
 
 java-operationBased-fragments_with_defer_and_include_directives                                  5392
 kotlin-compat-fragments_with_defer_and_include_directives                                        3613
 kotlin-operationBased-fragments_with_defer_and_include_directives                                3420
 kotlin-responseBased-fragment_with_inline_fragment                                               2378
-java-operationBased-fragment_with_inline_fragment                                                1844
+java-operationBased-fragment_with_inline_fragment                                                1845
 java-operationBased-nested_named_fragments                                                       1844
-java-operationBased-union_inline_fragments                                                       1616
-java-operationBased-unique_type_name                                                             1597
+java-operationBased-union_inline_fragments                                                       1617
+java-operationBased-unique_type_name                                                             1598
 kotlin-responseBased-nested_named_fragments                                                      1591
-java-operationBased-inline_fragment_intersection                                                 1584
+java-operationBased-inline_fragment_intersection                                                 1585
 java-operationBased-root_query_fragment_with_nested_fragments                                    1548
 kotlin-compat-fragment_with_inline_fragment                                                      1486
-java-operationBased-mutation_create_review                                                       1446
+java-operationBased-mutation_create_review                                                       1447
 java-operationBased-named_fragment_delegate                                                      1445
-java-operationBased-__schema                                                                     1373
+java-operationBased-__schema                                                                     1378
 kotlin-responseBased-named_fragment_delegate                                                     1339
 java-operationBased-named_fragment_with_variables                                                1325
 kotlin-responseBased-unique_type_name                                                            1323
 kotlin-compat-nested_named_fragments                                                             1310
-java-operationBased-nested_conditional_inline                                                    1282
+java-operationBased-nested_conditional_inline                                                    1283
 java-operationBased-fragment_used_twice                                                          1258
-java-operationBased-input_object_type                                                            1257
+java-operationBased-input_object_type                                                            1258
 kotlin-operationBased-fragment_with_inline_fragment                                              1249
 java-operationBased-multiple_fragments                                                           1247
-java-operationBased-mutation_create_review_semantic_naming                                       1242
+java-operationBased-mutation_create_review_semantic_naming                                       1243
 java-operationBased-nested_field_with_multiple_fieldsets                                         1241
 kotlin-responseBased-root_query_fragment_with_nested_fragments                                   1230
 kotlin-operationBased-nested_named_fragments                                                     1225
@@ -40,7 +40,7 @@ java-operationBased-two_heroes_with_friends
 java-operationBased-inline_fragment_merge_fields                                                 1195
 kotlin-responseBased-inline_fragment_intersection                                                1187
 kotlin-compat-inline_fragment_intersection                                                       1174
-java-operationBased-named_fragment_inside_inline_fragment                                        1143
+java-operationBased-named_fragment_inside_inline_fragment                                        1144
 java-operationBased-fragments_with_type_condition                                                1139
 kotlin-compat-unique_type_name                                                                   1123
 kotlin-operationBased-inline_fragment_intersection                                               1111
@@ -48,16 +48,16 @@ kotlin-operationBased-union_inline_fragments
 kotlin-responseBased-fragment_used_twice                                                         1108
 kotlin-responseBased-union_inline_fragments                                                      1100
 kotlin-responseBased-__schema                                                                    1092
-java-operationBased-target_name                                                                  1085
+java-operationBased-target_name                                                                  1086
 kotlin-operationBased-unique_type_name                                                           1080
-java-operationBased-root_query_inline_fragment                                                   1078
+java-operationBased-root_query_inline_fragment                                                   1079
 kotlin-compat-root_query_fragment_with_nested_fragments                                          1073
 kotlin-compat-union_inline_fragments                                                             1069
 kotlin-responseBased-fragments_with_type_condition                                               1061
 java-operationBased-simple_fragment_with_inline_fragments                                        1031
 kotlin-responseBased-multiple_fragments                                                          1028
 kotlin-responseBased-mutation_create_review                                                      1026
-java-operationBased-inline_fragments_with_friends                                                1019
+java-operationBased-inline_fragments_with_friends                                                1020
 kotlin-operationBased-root_query_fragment_with_nested_fragments                                  1019
 kotlin-responseBased-simple_fragment_with_inline_fragments                                       1019
 java-operationBased-fragment_spread_with_nested_fields                                           1015
@@ -73,7 +73,7 @@ java-operationBased-fragments_same_type_condition
 java-operationBased-simple_union                                                                  933
 kotlin-compat-named_fragment_with_variables                                                       919
 java-operationBased-deprecated_merged_field                                                       913
-java-operationBased-hero_details                                                                  904
+java-operationBased-hero_details                                                                  905
 java-operationBased-not_all_combinations_are_needed                                               903
 java-operationBased-fieldset_with_multiple_super                                                  887
 java-operationBased-simple_inline_fragment                                                        887
@@ -130,8 +130,8 @@ kotlin-operationBased-simple_fragment
 java-operationBased-root_query_fragment                                                           684
 kotlin-operationBased-fragment_spread_with_nested_fields                                          682
 kotlin-compat-fragments_same_type_condition                                                       673
+java-operationBased-input_object_variable_and_argument                                            670
 kotlin-compat-simple_union                                                                        670
-java-operationBased-input_object_variable_and_argument                                            669
 kotlin-compat-deprecated_merged_field                                                             662
 java-operationBased-monomorphic                                                                   657
 kotlin-compat-inline_fragment_with_include_directive                                              656
@@ -139,7 +139,7 @@ java-operationBased-interface_always_nested
 kotlin-compat-union_fragment                                                                      654
 kotlin-compat-not_all_combinations_are_needed                                                     653
 kotlin-compat-inline_fragment_inside_inline_fragment                                              647
-java-operationBased-deprecation                                                                   645
+java-operationBased-deprecation                                                                   646
 kotlin-operationBased-fragments_same_type_condition                                               642
 kotlin-operationBased-simple_union                                                                639
 java-operationBased-capitalized_fields                                                            636
@@ -149,7 +149,7 @@ java-operationBased-recursive_selection
 kotlin-compat-fieldset_with_multiple_super                                                        632
 kotlin-responseBased-fragment_with_multiple_fieldsets                                             629
 kotlin-compat-named_fragment_without_implementation                                               626
-java-operationBased-hero_with_review                                                              624
+java-operationBased-hero_with_review                                                              625
 kotlin-responseBased-named_fragment_without_implementation                                        622
 kotlin-operationBased-deprecated_merged_field                                                     619
 kotlin-responseBased-hero_details                                                                 615
@@ -158,21 +158,21 @@ kotlin-operationBased-not_all_combinations_are_needed
 kotlin-operationBased-union_fragment                                                              612
 kotlin-responseBased-inline_fragment_merge_fields                                                 609
 kotlin-compat-inline_fragment_merge_fields                                                        607
+java-operationBased-hero_name_query_long_name                                                     605
 kotlin-operationBased-inline_fragment_with_include_directive                                      605
 kotlin-operationBased-fieldset_with_multiple_super                                                604
-java-operationBased-hero_name_query_long_name                                                     604
 kotlin-responseBased-inline_fragment_inside_inline_fragment                                       602
 java-operationBased-custom_scalar_type                                                            601
 java-operationBased-field_with_include_directive                                                  601
+java-operationBased-variable_default_value                                                        599
 kotlin-operationBased-simple_inline_fragment                                                      598
-java-operationBased-variable_default_value                                                        598
 java-operationBased-hero_name                                                                     596
 kotlin-operationBased-named_fragment_without_implementation                                       595
 kotlin-compat-test_inline                                                                         588
 kotlin-responseBased-simple_inline_fragment                                                       586
 kotlin-responseBased-fieldset_with_multiple_super                                                 585
 kotlin-responseBased-not_all_combinations_are_needed                                              585
-java-operationBased-optional                                                                      574
+java-operationBased-optional                                                                      575
 kotlin-compat-simple_inline_fragment                                                              568
 java-operationBased-inline_fragment_for_non_optional_field                                        565
 kotlin-operationBased-test_inline                                                                 565
@@ -219,12 +219,12 @@ kotlin-responseBased-monomorphic
 java-operationBased-merged_include                                                                448
 java-operationBased-operation_id_generator                                                        448
 kotlin-responseBased-inline_fragment_for_non_optional_field                                       447
+java-operationBased-enum_field                                                                    443
 kotlin-responseBased-variable_default_value                                                       443
-java-operationBased-enum_field                                                                    442
-java-operationBased-enums_as_sealed                                                               436
+java-operationBased-enums_as_sealed                                                               437
 kotlin-operationBased-hero_name                                                                   436
 kotlin-operationBased-capitalized_fields                                                          435
-java-operationBased-case_sensitive_enum                                                           433
+java-operationBased-case_sensitive_enum                                                           434
 kotlin-responseBased-field_with_include_directive                                                 431
 kotlin-responseBased-optional                                                                     431
 java-operationBased-nonnull                                                                       429
diff --git a/apollo-compiler/src/test/graphql/com/example/mutation_create_review/java/operationBased/mutation_create_review/type/Episode.java.expected b/apollo-compiler/src/test/graphql/com/example/mutation_create_review/java/operationBased/mutation_create_review/type/Episode.java.expected
index 4438522823..572b111bf2 100644
--- a/apollo-compiler/src/test/graphql/com/example/mutation_create_review/java/operationBased/mutation_create_review/type/Episode.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/mutation_create_review/java/operationBased/mutation_create_review/type/Episode.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * The episodes in the Star Wars trilogy
  */
 public class Episode {
-  public static EnumType type = new EnumType("Episode");
+  public static EnumType type = new EnumType("Episode", Arrays.asList("NEWHOPE", "EMPIRE", "JEDI", "DEPRECATED", "new"));
 
   public static Episode NEWHOPE = new Episode("NEWHOPE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/mutation_create_review_semantic_naming/java/operationBased/mutation_create_review_semantic_naming/type/Episode.java.expected b/apollo-compiler/src/test/graphql/com/example/mutation_create_review_semantic_naming/java/operationBased/mutation_create_review_semantic_naming/type/Episode.java.expected
index 4f70689fdd..87c721099f 100644
--- a/apollo-compiler/src/test/graphql/com/example/mutation_create_review_semantic_naming/java/operationBased/mutation_create_review_semantic_naming/type/Episode.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/mutation_create_review_semantic_naming/java/operationBased/mutation_create_review_semantic_naming/type/Episode.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * The episodes in the Star Wars trilogy
  */
 public class Episode {
-  public static EnumType type = new EnumType("Episode");
+  public static EnumType type = new EnumType("Episode", Arrays.asList("NEWHOPE", "EMPIRE", "JEDI", "DEPRECATED", "new"));
 
   public static Episode NEWHOPE = new Episode("NEWHOPE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/named_fragment_inside_inline_fragment/java/operationBased/named_fragment_inside_inline_fragment/type/Episode.java.expected b/apollo-compiler/src/test/graphql/com/example/named_fragment_inside_inline_fragment/java/operationBased/named_fragment_inside_inline_fragment/type/Episode.java.expected
index 6cebe4e3eb..677d041687 100644
--- a/apollo-compiler/src/test/graphql/com/example/named_fragment_inside_inline_fragment/java/operationBased/named_fragment_inside_inline_fragment/type/Episode.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/named_fragment_inside_inline_fragment/java/operationBased/named_fragment_inside_inline_fragment/type/Episode.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * The episodes in the Star Wars trilogy
  */
 public class Episode {
-  public static EnumType type = new EnumType("Episode");
+  public static EnumType type = new EnumType("Episode", Arrays.asList("NEWHOPE", "EMPIRE", "JEDI", "DEPRECATED", "new"));
 
   public static Episode NEWHOPE = new Episode("NEWHOPE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/nested_conditional_inline/java/operationBased/nested_conditional_inline/type/Episode.java.expected b/apollo-compiler/src/test/graphql/com/example/nested_conditional_inline/java/operationBased/nested_conditional_inline/type/Episode.java.expected
index e99bdc6f19..8fc0707907 100644
--- a/apollo-compiler/src/test/graphql/com/example/nested_conditional_inline/java/operationBased/nested_conditional_inline/type/Episode.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/nested_conditional_inline/java/operationBased/nested_conditional_inline/type/Episode.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * The episodes in the Star Wars trilogy
  */
 public class Episode {
-  public static EnumType type = new EnumType("Episode");
+  public static EnumType type = new EnumType("Episode", Arrays.asList("NEWHOPE", "EMPIRE", "JEDI", "DEPRECATED", "new"));
 
   public static Episode NEWHOPE = new Episode("NEWHOPE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/optional/java/operationBased/optional/type/Episode.java.expected b/apollo-compiler/src/test/graphql/com/example/optional/java/operationBased/optional/type/Episode.java.expected
index 71ac62a99f..f8a0e1d069 100644
--- a/apollo-compiler/src/test/graphql/com/example/optional/java/operationBased/optional/type/Episode.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/optional/java/operationBased/optional/type/Episode.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * The episodes in the Star Wars trilogy
  */
 public class Episode {
-  public static EnumType type = new EnumType("Episode");
+  public static EnumType type = new EnumType("Episode", Arrays.asList("NEWHOPE", "EMPIRE", "JEDI", "DEPRECATED", "new"));
 
   public static Episode NEWHOPE = new Episode("NEWHOPE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/root_query_inline_fragment/java/operationBased/root_query_inline_fragment/type/Episode.java.expected b/apollo-compiler/src/test/graphql/com/example/root_query_inline_fragment/java/operationBased/root_query_inline_fragment/type/Episode.java.expected
index e043ce2ea0..4d2b2bd3de 100644
--- a/apollo-compiler/src/test/graphql/com/example/root_query_inline_fragment/java/operationBased/root_query_inline_fragment/type/Episode.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/root_query_inline_fragment/java/operationBased/root_query_inline_fragment/type/Episode.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * The episodes in the Star Wars trilogy
  */
 public class Episode {
-  public static EnumType type = new EnumType("Episode");
+  public static EnumType type = new EnumType("Episode", Arrays.asList("NEWHOPE", "EMPIRE", "JEDI", "DEPRECATED", "new"));
 
   public static Episode NEWHOPE = new Episode("NEWHOPE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/target_name/java/operationBased/target_name/type/renamedEnum.java.expected b/apollo-compiler/src/test/graphql/com/example/target_name/java/operationBased/target_name/type/renamedEnum.java.expected
index 334672978b..79ef237c0e 100644
--- a/apollo-compiler/src/test/graphql/com/example/target_name/java/operationBased/target_name/type/renamedEnum.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/target_name/java/operationBased/target_name/type/renamedEnum.java.expected
@@ -9,9 +9,10 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 public class renamedEnum {
-  public static EnumType type = new EnumType("ReservedEnum");
+  public static EnumType type = new EnumType("ReservedEnum", Arrays.asList("VALUE"));
 
   public static renamedEnum VALUE = new renamedEnum("VALUE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/union_inline_fragments/java/operationBased/union_inline_fragments/type/Episode.java.expected b/apollo-compiler/src/test/graphql/com/example/union_inline_fragments/java/operationBased/union_inline_fragments/type/Episode.java.expected
index 0d9748a0fb..21e0c0aae9 100644
--- a/apollo-compiler/src/test/graphql/com/example/union_inline_fragments/java/operationBased/union_inline_fragments/type/Episode.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/union_inline_fragments/java/operationBased/union_inline_fragments/type/Episode.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * The episodes in the Star Wars trilogy
  */
 public class Episode {
-  public static EnumType type = new EnumType("Episode");
+  public static EnumType type = new EnumType("Episode", Arrays.asList("NEWHOPE", "EMPIRE", "JEDI", "DEPRECATED", "new"));
 
   public static Episode NEWHOPE = new Episode("NEWHOPE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/unique_type_name/java/operationBased/unique_type_name/type/Episode.java.expected b/apollo-compiler/src/test/graphql/com/example/unique_type_name/java/operationBased/unique_type_name/type/Episode.java.expected
index 24d31b2f44..cb22524590 100644
--- a/apollo-compiler/src/test/graphql/com/example/unique_type_name/java/operationBased/unique_type_name/type/Episode.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/unique_type_name/java/operationBased/unique_type_name/type/Episode.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * The episodes in the Star Wars trilogy
  */
 public class Episode {
-  public static EnumType type = new EnumType("Episode");
+  public static EnumType type = new EnumType("Episode", Arrays.asList("NEWHOPE", "EMPIRE", "JEDI", "DEPRECATED", "new"));
 
   public static Episode NEWHOPE = new Episode("NEWHOPE");
 
diff --git a/apollo-compiler/src/test/graphql/com/example/variable_default_value/java/operationBased/variable_default_value/type/Episode.java.expected b/apollo-compiler/src/test/graphql/com/example/variable_default_value/java/operationBased/variable_default_value/type/Episode.java.expected
index 21d11e11c4..8154c6bfbb 100644
--- a/apollo-compiler/src/test/graphql/com/example/variable_default_value/java/operationBased/variable_default_value/type/Episode.java.expected
+++ b/apollo-compiler/src/test/graphql/com/example/variable_default_value/java/operationBased/variable_default_value/type/Episode.java.expected
@@ -9,12 +9,13 @@ import com.apollographql.apollo3.api.EnumType;
 import java.lang.Object;
 import java.lang.Override;
 import java.lang.String;
+import java.util.Arrays;
 
 /**
  * The episodes in the Star Wars trilogy
  */
 public class Episode {
-  public static EnumType type = new EnumType("Episode");
+  public static EnumType type = new EnumType("Episode", Arrays.asList("NEWHOPE", "EMPIRE", "JEDI", "DEPRECATED", "new"));
 
   public static Episode NEWHOPE = new Episode("NEWHOPE");
 
diff --git a/apollo-compiler/src/test/kotlin/com/apollographql/apollo3/compiler/FieldsOnDisjointTypesMustMergeTest.kt b/apollo-compiler/src/test/kotlin/com/apollographql/apollo3/compiler/FieldsOnDisjointTypesMustMergeTest.kt
new file mode 100644
index 0000000000..cd903582f0
--- /dev/null
+++ b/apollo-compiler/src/test/kotlin/com/apollographql/apollo3/compiler/FieldsOnDisjointTypesMustMergeTest.kt
@@ -0,0 +1,33 @@
+package com.apollographql.apollo3.compiler
+
+import com.apollographql.apollo3.ast.parseAsGQLDocument
+import com.apollographql.apollo3.ast.validateAsExecutable
+import com.apollographql.apollo3.compiler.TestUtils.checkExpected
+import com.apollographql.apollo3.compiler.TestUtils.findSchema
+import com.apollographql.apollo3.compiler.TestUtils.serialize
+import okio.buffer
+import okio.source
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import java.io.File
+
+class FieldsOnDisjointTypesMustMergeTest {
+  private val graphQLFile = File("src/test/validation/operation/fields_on_disjoint_types_must_merge/different_shapes.graphql")
+
+  @Test
+  fun testEnableFieldsOnDisjointTypesMustMerge() = checkExpected(graphQLFile) { schema ->
+    val parseResult = graphQLFile.source().buffer().parseAsGQLDocument(filePath = graphQLFile.name)
+    val issues = parseResult.valueAssertNoErrors().validateAsExecutable(schema = schema!!, fieldsOnDisjointTypesMustMerge = true).issues
+    issues.serialize()
+  }
+
+  @Test
+  fun testDisableFieldsOnDisjointTypesMustMerge() {
+    val schema = findSchema(graphQLFile.parentFile)!!
+    val parseResult = graphQLFile.source().buffer().parseAsGQLDocument(filePath = graphQLFile.name)
+
+    val issues = parseResult.valueAssertNoErrors().validateAsExecutable(schema = schema, fieldsOnDisjointTypesMustMerge = false).issues
+
+    assertTrue(issues.isEmpty())
+  }
+}
diff --git a/apollo-compiler/src/test/kotlin/com/apollographql/apollo3/compiler/TestUtils.kt b/apollo-compiler/src/test/kotlin/com/apollographql/apollo3/compiler/TestUtils.kt
index 4f6fe91138..923526ea97 100644
--- a/apollo-compiler/src/test/kotlin/com/apollographql/apollo3/compiler/TestUtils.kt
+++ b/apollo-compiler/src/test/kotlin/com/apollographql/apollo3/compiler/TestUtils.kt
@@ -1,15 +1,16 @@
 package com.apollographql.apollo3.compiler
 
+import com.apollographql.apollo3.ast.Issue
 import com.apollographql.apollo3.ast.Schema
-import com.apollographql.apollo3.ast.introspection.toSchema
 import com.apollographql.apollo3.ast.introspection.toSchemaGQLDocument
-import com.apollographql.apollo3.ast.validateAsSchema
 import com.apollographql.apollo3.ast.validateAsSchemaAndAddApolloDefinition
 import com.google.common.truth.Truth.assertThat
 import okio.Buffer
 import java.io.File
 
 internal object TestUtils {
+  private const val separator = "\n------------\n"
+
   internal fun shouldUpdateTestFixtures(): Boolean {
     if (System.getenv("updateTestFixtures") != null) {
       return true
@@ -67,7 +68,7 @@ internal object TestUtils {
     return File(parentFile, "$nameWithoutExtension.$newExtension")
   }
 
-  private fun findSchema(dir: File): Schema? {
+  fun findSchema(dir: File): Schema? {
     return listOf("graphqls", "sdl", "json").map { File(dir, "schema.$it") }
         .firstOrNull { it.exists() }
         ?.let {
@@ -114,6 +115,10 @@ internal object TestUtils {
       assertThat(actual).isEqualTo(expected)
     }
   }
+
+  fun List<Issue>.serialize() = joinToString(separator) {
+    "${it.severity}: ${it.javaClass.simpleName} (${it.sourceLocation.line}:${it.sourceLocation.position})\n${it.message}"
+  }
 }
 
 internal fun String.buffer() = Buffer().writeUtf8(this)
diff --git a/apollo-compiler/src/test/kotlin/com/apollographql/apollo3/compiler/ValidationTest.kt b/apollo-compiler/src/test/kotlin/com/apollographql/apollo3/compiler/ValidationTest.kt
index 167b147ff5..228b3dc357 100644
--- a/apollo-compiler/src/test/kotlin/com/apollographql/apollo3/compiler/ValidationTest.kt
+++ b/apollo-compiler/src/test/kotlin/com/apollographql/apollo3/compiler/ValidationTest.kt
@@ -1,10 +1,10 @@
 package com.apollographql.apollo3.compiler
 
-import com.apollographql.apollo3.ast.Issue
 import com.apollographql.apollo3.ast.parseAsGQLDocument
 import com.apollographql.apollo3.ast.validateAsExecutable
 import com.apollographql.apollo3.ast.validateAsSchemaAndAddApolloDefinition
 import com.apollographql.apollo3.compiler.TestUtils.checkExpected
+import com.apollographql.apollo3.compiler.TestUtils.serialize
 import com.apollographql.apollo3.compiler.TestUtils.testParametersForGraphQLFilesIn
 import okio.buffer
 import okio.source
@@ -16,11 +16,6 @@ import java.io.File
 @Suppress("UNUSED_PARAMETER")
 @RunWith(Parameterized::class)
 class ValidationTest(name: String, private val graphQLFile: File) {
-  private val separator = "\n------------\n"
-
-  private fun List<Issue>.serialize() = joinToString(separator) {
-    "${it.severity}: ${it.javaClass.simpleName} (${it.sourceLocation.line}:${it.sourceLocation.position})\n${it.message}"
-  }
 
   @Test
   fun testValidation() = checkExpected(graphQLFile) { schema ->
@@ -31,7 +26,8 @@ class ValidationTest(name: String, private val graphQLFile: File) {
       if (parseResult.issues.isNotEmpty()) {
         parseResult.issues
       } else {
-        parseResult.valueAssertNoErrors().validateAsExecutable(schema = schema!!).issues + if (graphQLFile.name == "capitalized_fields_disallowed.graphql") {
+        val mustMerge = graphQLFile.name != "merging_allowed.graphql"
+        parseResult.valueAssertNoErrors().validateAsExecutable(schema = schema!!, fieldsOnDisjointTypesMustMerge = mustMerge).issues + if (graphQLFile.name == "capitalized_fields_disallowed.graphql") {
           checkCapitalizedFields(parseResult.value!!.definitions)
         } else {
           emptyList()
diff --git a/apollo-compiler/src/test/kotlin/com/apollographql/apollo3/compiler/conditionalFragments/defer.graphql b/apollo-compiler/src/test/kotlin/com/apollographql/apollo3/compiler/conditionalFragments/defer.graphql
index f4bf4129a3..5422c866c0 100644
--- a/apollo-compiler/src/test/kotlin/com/apollographql/apollo3/compiler/conditionalFragments/defer.graphql
+++ b/apollo-compiler/src/test/kotlin/com/apollographql/apollo3/compiler/conditionalFragments/defer.graphql
@@ -1,6 +1,6 @@
 query QueryWithDefer($withDetails: Boolean!) {
   field1
-  ... on Query @experimental_defer(if: $withDetails) {
+  ... on Query @defer(if: $withDetails) {
     field2
   }
 }
diff --git a/apollo-compiler/src/test/validation/operation/defer/duplicate_labels.graphql b/apollo-compiler/src/test/validation/operation/defer/duplicate_labels.graphql
index 407e056bdd..e610fbb55d 100644
--- a/apollo-compiler/src/test/validation/operation/defer/duplicate_labels.graphql
+++ b/apollo-compiler/src/test/validation/operation/defer/duplicate_labels.graphql
@@ -1,12 +1,12 @@
 query WithFragmentSpreads {
   computers {
-    ...ComputerFields @experimental_defer(label: "foobar")
+    ...ComputerFields @defer(label: "foobar")
   }
 }
 
 fragment ComputerFields on Computer {
   screen {
-    ...ScreenFields @experimental_defer(label: "foobar")
+    ...ScreenFields @defer(label: "foobar")
   }
 }
 
diff --git a/apollo-compiler/src/test/validation/operation/defer/duplicate_path_and_labels_inline.graphql b/apollo-compiler/src/test/validation/operation/defer/duplicate_path_and_labels_inline.graphql
index e92bbe2dc5..f0e9b6e4c6 100644
--- a/apollo-compiler/src/test/validation/operation/defer/duplicate_path_and_labels_inline.graphql
+++ b/apollo-compiler/src/test/validation/operation/defer/duplicate_path_and_labels_inline.graphql
@@ -6,10 +6,10 @@ query WithInlineFragments {
       year
       screen {
         resolution
-        ... on Screen @experimental_defer {
+        ... on Screen @defer {
           isColor
         }
-        ... on HasId @experimental_defer {
+        ... on HasId @defer {
           id
         }
       }
diff --git a/apollo-compiler/src/test/validation/operation/defer/duplicate_path_and_labels_spread.graphql b/apollo-compiler/src/test/validation/operation/defer/duplicate_path_and_labels_spread.graphql
index e632ecca53..35c439e7c0 100644
--- a/apollo-compiler/src/test/validation/operation/defer/duplicate_path_and_labels_spread.graphql
+++ b/apollo-compiler/src/test/validation/operation/defer/duplicate_path_and_labels_spread.graphql
@@ -7,13 +7,13 @@ query WithFragmentSpreads {
 
 fragment ComputerFields on Computer {
   screen {
-    ...ScreenFields @experimental_defer
+    ...ScreenFields @defer
   }
 }
 
 fragment ComputerFields2 on Computer {
   screen {
-    ...ScreenFields @experimental_defer
+    ...ScreenFields @defer
   }
 }
 
diff --git a/apollo-compiler/src/test/validation/operation/defer/fragment_used_twice_not_duplicate_labels.graphql b/apollo-compiler/src/test/validation/operation/defer/fragment_used_twice_not_duplicate_labels.graphql
index 13d8f5607d..37e766f87b 100644
--- a/apollo-compiler/src/test/validation/operation/defer/fragment_used_twice_not_duplicate_labels.graphql
+++ b/apollo-compiler/src/test/validation/operation/defer/fragment_used_twice_not_duplicate_labels.graphql
@@ -1,14 +1,14 @@
 query Query1 {
   computers {
     id
-    ...ComputerFields @experimental_defer
+    ...ComputerFields @defer
   }
 }
 
 query Query2 {
   computers {
     id
-    ...ComputerFields @experimental_defer
+    ...ComputerFields @defer
   }
 }
 
@@ -18,7 +18,7 @@ fragment ComputerFields on Computer {
   screen {
     resolution
     # This is traversed twice, but it's not a duplicate label
-    ...ScreenFields @experimental_defer(label: "a")
+    ...ScreenFields @defer(label: "a")
   }
 }
 
diff --git a/apollo-compiler/src/test/validation/operation/defer/illegal_label.graphql b/apollo-compiler/src/test/validation/operation/defer/illegal_label.graphql
index 9a17a78441..3c865e04a4 100644
--- a/apollo-compiler/src/test/validation/operation/defer/illegal_label.graphql
+++ b/apollo-compiler/src/test/validation/operation/defer/illegal_label.graphql
@@ -1,6 +1,6 @@
 query GetAnimal {
   animal {
-    ... on Cat @experimental_defer(label: "a/b") {
+    ... on Cat @defer(label: "a/b") {
       meow
     }
   }
diff --git a/apollo-compiler/src/test/validation/operation/defer/label_is_a_variable.graphql b/apollo-compiler/src/test/validation/operation/defer/label_is_a_variable.graphql
index 5b73ff9759..e334978700 100644
--- a/apollo-compiler/src/test/validation/operation/defer/label_is_a_variable.graphql
+++ b/apollo-compiler/src/test/validation/operation/defer/label_is_a_variable.graphql
@@ -1,6 +1,6 @@
 query GetAnimal($label: String) {
   animal {
-    ... on Cat @experimental_defer(label: $label) {
+    ... on Cat @defer(label: $label) {
       meow
     }
   }
diff --git a/apollo-compiler/src/test/validation/operation/defer/root_field_mutation_or_subscription.graphql b/apollo-compiler/src/test/validation/operation/defer/root_field_mutation_or_subscription.graphql
index 5dbac92583..c55d0590cc 100644
--- a/apollo-compiler/src/test/validation/operation/defer/root_field_mutation_or_subscription.graphql
+++ b/apollo-compiler/src/test/validation/operation/defer/root_field_mutation_or_subscription.graphql
@@ -1,5 +1,5 @@
 query GetAnimalQuery {
-  ... on Query @experimental_defer {
+  ... on Query @defer {
     animal {
       id
     }
@@ -7,7 +7,7 @@ query GetAnimalQuery {
 }
 
 subscription GetAnimalSubscription {
-  ... on Subscription @experimental_defer {
+  ... on Subscription @defer {
     animal {
       id
     }
@@ -15,7 +15,7 @@ subscription GetAnimalSubscription {
 }
 
 mutation CreateAnimalMutation {
-  ... on Mutation @experimental_defer {
+  ... on Mutation @defer {
     createSession
   }
 }
diff --git a/apollo-compiler/src/test/validation/operation/fields_in_set_can_merge/merging_allowed.expected b/apollo-compiler/src/test/validation/operation/fields_in_set_can_merge/merging_allowed.expected
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/apollo-compiler/src/test/validation/operation/fields_in_set_can_merge/merging_allowed.graphql b/apollo-compiler/src/test/validation/operation/fields_in_set_can_merge/merging_allowed.graphql
new file mode 100644
index 0000000000..8ada2689f9
--- /dev/null
+++ b/apollo-compiler/src/test/validation/operation/fields_in_set_can_merge/merging_allowed.graphql
@@ -0,0 +1,10 @@
+query GetAnimal {
+    animal {
+        ... on Cat {
+            meow
+        }
+        ... on Dog {
+            meow: id
+        }
+    }
+}
\ No newline at end of file
diff --git a/apollo-compiler/src/test/validation/operation/fields_on_disjoint_types_must_merge/different_shapes.expected b/apollo-compiler/src/test/validation/operation/fields_on_disjoint_types_must_merge/different_shapes.expected
new file mode 100644
index 0000000000..056e136ebf
--- /dev/null
+++ b/apollo-compiler/src/test/validation/operation/fields_on_disjoint_types_must_merge/different_shapes.expected
@@ -0,0 +1,11 @@
+ERROR: ValidationError (9:6)
+`value` cannot be merged with `value` (at different_shapes.graphql: (12, 7)): they have different shapes. Use different aliases on the fields to fetch both if this was intentional.
+------------
+ERROR: ValidationError (12:6)
+`value` cannot be merged with `value` (at different_shapes.graphql: (9, 7)): they have different shapes. Use different aliases on the fields to fetch both if this was intentional.
+------------
+ERROR: ValidationError (9:6)
+`value` cannot be merged with `value` (at different_shapes.graphql: (12, 7)): they have different shapes. Use different aliases on the fields to fetch both if this was intentional.
+------------
+ERROR: ValidationError (12:6)
+`value` cannot be merged with `value` (at different_shapes.graphql: (9, 7)): they have different shapes. Use different aliases on the fields to fetch both if this was intentional.
\ No newline at end of file
diff --git a/apollo-compiler/src/test/validation/operation/fields_on_disjoint_types_must_merge/different_shapes.graphql b/apollo-compiler/src/test/validation/operation/fields_on_disjoint_types_must_merge/different_shapes.graphql
new file mode 100644
index 0000000000..92f3c2b2ed
--- /dev/null
+++ b/apollo-compiler/src/test/validation/operation/fields_on_disjoint_types_must_merge/different_shapes.graphql
@@ -0,0 +1,14 @@
+query GetFoo {
+  foo {
+    ...PropertyValue
+  }
+}
+fragment PropertyValue on PropertyValue {
+  __typename
+  ... on PropertyValueBoolean {
+      value
+  }
+  ... on PropertyValueInt {
+      value
+  }
+}
\ No newline at end of file
diff --git a/apollo-compiler/src/test/validation/operation/fields_on_disjoint_types_must_merge/schema.graphqls b/apollo-compiler/src/test/validation/operation/fields_on_disjoint_types_must_merge/schema.graphqls
new file mode 100644
index 0000000000..98daea9cd1
--- /dev/null
+++ b/apollo-compiler/src/test/validation/operation/fields_on_disjoint_types_must_merge/schema.graphqls
@@ -0,0 +1,13 @@
+type Query {
+  foo: PropertyValue
+}
+union PropertyValue = PropertyValueBoolean | PropertyValueInt
+
+type PropertyValueBoolean {
+  name: String!
+  value: Boolean
+}
+type PropertyValueInt {
+  name: String!
+  value: Int
+}
\ No newline at end of file
diff --git a/apollo-runtime/src/commonTest/kotlin/com/apollographql/apollo3/internal/DeferJsonMergerTest.kt b/apollo-runtime/src/commonTest/kotlin/com/apollographql/apollo3/internal/DeferJsonMergerTest.kt
index 4264f9eb75..5b06a81f20 100644
--- a/apollo-runtime/src/commonTest/kotlin/com/apollographql/apollo3/internal/DeferJsonMergerTest.kt
+++ b/apollo-runtime/src/commonTest/kotlin/com/apollographql/apollo3/internal/DeferJsonMergerTest.kt
@@ -12,11 +12,10 @@ import kotlin.test.assertEquals
 
 class DeferJsonMergerTest {
   @Test
-  @Suppress("UNCHECKED_CAST")
-  fun mergeJson() {
-    val deferredJsonMerger = DeferredJsonMerger()
+  fun mergeJsonSingleIncrementalItem() {
+      val deferredJsonMerger = DeferredJsonMerger()
 
-    val payload1 = """
+      val payload1 = """
       {
         "data": {
           "computers": [
@@ -44,25 +43,29 @@ class DeferJsonMergerTest {
 
     val payload2 = """
       {
-        "data": {
-          "cpu": "386",
-          "year": 1993,
-          "screen": {
-            "resolution": "640x480"
+        "incremental": [
+          {
+            "data": {
+              "cpu": "386",
+              "year": 1993,
+              "screen": {
+                "resolution": "640x480"
+              }
+            },
+            "path": [
+              "computers",
+              0
+            ],
+            "label": "query:Query1:0",
+            "extensions": {
+              "duration": {
+                "amount": 100,
+                "unit": "ms"
+              }
+            }
           }
-        },
-        "path": [
-          "computers",
-          0
         ],
-        "label": "query:Query1:0",
-        "hasNext": true,
-        "extensions": {
-          "duration": {
-            "amount": 100,
-            "unit": "ms"
-          }
-        }
+        "hasNext": true
       }
     """
     val mergedPayloads_1_2 = """
@@ -88,10 +91,14 @@ class DeferJsonMergerTest {
         },
         "hasNext": true,
         "extensions": {
-          "duration": {
-            "amount": 100,
-            "unit": "ms"
-          }
+          "incremental": [
+            {
+              "duration": {
+                "amount": 100,
+                "unit": "ms"
+              }
+            }
+          ]
         }
       }      
     """
@@ -103,27 +110,31 @@ class DeferJsonMergerTest {
 
 
     val payload3 = """
-      {
-        "data": {
-          "cpu": "486",
-          "year": 1996,
-          "screen": {
-            "resolution": "640x480"
-          }
-        },
-        "path": [
-          "computers",
-          1
-        ],
-        "label": "query:Query1:0",
-        "hasNext": true,
-        "extensions": {
-          "duration": {
-            "amount": 25,
-            "unit": "ms"
-          }
+        {
+          "incremental": [
+            {
+              "data": {
+                "cpu": "486",
+                "year": 1996,
+                "screen": {
+                  "resolution": "640x480"
+                }
+              },
+              "path": [
+                "computers",
+                1
+              ],
+              "label": "query:Query1:0",
+              "extensions": {
+                "duration": {
+                  "amount": 25,
+                  "unit": "ms"
+                }
+              }
+            }
+          ],
+          "hasNext": true
         }
-      }
     """
     val mergedPayloads_1_2_3 = """
       {
@@ -151,10 +162,14 @@ class DeferJsonMergerTest {
         },
         "hasNext": true,
         "extensions": {
-          "duration": {
-            "amount": 25,
-            "unit": "ms"
-          }
+          "incremental": [
+            {
+              "duration": {
+                "amount": 25,
+                "unit": "ms"
+              }
+            }
+          ]
         }
       }
     """
@@ -167,33 +182,37 @@ class DeferJsonMergerTest {
 
 
     val payload4 = """
-      {
-        "data": null,
-        "path": [
-          "computers",
-          0,
-          "screen"
-        ],
-        "errors": [
-          {
-            "message": "Cannot resolve isColor",
-            "locations": [
-              {
-                "line": 12,
-                "column": 11
-              }
-            ],
-            "path": [
-              "computers",
-              0,
-              "screen",
-              "isColor"
-            ]
-          }
-        ],
-        "label": "fragment:ComputerFields:0",
-        "hasNext": true
-      }
+        {
+          "incremental": [
+            {
+              "data": null,
+              "path": [
+                "computers",
+                0,
+                "screen"
+              ],
+              "errors": [
+                {
+                  "message": "Cannot resolve isColor",
+                  "locations": [
+                    {
+                      "line": 12,
+                      "column": 11
+                    }
+                  ],
+                  "path": [
+                    "computers",
+                    0,
+                    "screen",
+                    "isColor"
+                  ]
+                }
+              ],
+              "label": "fragment:ComputerFields:0"
+            }
+          ],
+          "hasNext": true
+        }
     """
     val mergedPayloads_1_2_3_4 = """
       {
@@ -246,16 +265,80 @@ class DeferJsonMergerTest {
         DeferredFragmentIdentifier(path = listOf("computers", 1), label = "query:Query1:0"),
     ), deferredJsonMerger.mergedFragmentIds)
 
+
     val payload5 = """
+        {
+          "incremental": [
+            {
+              "data": {
+                "isColor": false
+              },
+              "path": [
+                "computers",
+                1,
+                "screen"
+              ],
+              "errors": [
+                {
+                  "message": "Another error",
+                  "locations": [
+                    {
+                      "line": 1,
+                      "column": 1
+                    }
+                  ]
+                }
+              ],
+              "label": "fragment:ComputerFields:0",
+              "extensions": {
+                "value": 42,
+                "duration": {
+                  "amount": 130,
+                  "unit": "ms"
+                }
+              }
+            }
+          ],
+          "hasNext": false
+        }
+    """
+    val mergedPayloads_1_2_3_4_5 = """
       {
         "data": {
-          "isColor": false
+          "computers": [
+            {
+              "id": "Computer1",
+              "cpu": "386",
+              "year": 1993,
+              "screen": {
+                "isTouch": true,
+                "resolution": "640x480"
+              }
+            },
+            {
+              "id": "Computer2",
+              "cpu": "486",
+              "year": 1996,
+              "screen": {
+                "isTouch": false,
+                "resolution": "640x480",
+                "isColor": false
+              }
+            }
+          ]
+        },
+        "hasNext": true,
+        "extensions": {
+          "incremental": [
+            {
+              "value": 42,
+              "duration": {
+                "amount": 130,
+                "unit": "ms"
+              }
+            }
+          ]
         },
-        "path": [
-          "computers",
-          1,
-          "screen"
-        ],
         "errors": [
           {
             "message": "Another error",
@@ -266,19 +349,209 @@ class DeferJsonMergerTest {
               }
             ]
           }
-        ],
-        "label": "fragment:ComputerFields:0",
-        "hasNext": false,
-        "extensions": {
-          "value": 42,
-          "duration": {
-            "amount": 130,
-            "unit": "ms"
+        ]
+      }
+    """
+      deferredJsonMerger.merge(payload5.buffer())
+      assertEquals(jsonToMap(mergedPayloads_1_2_3_4_5), deferredJsonMerger.merged)
+      assertEquals(setOf(
+          DeferredFragmentIdentifier(path = listOf("computers", 0), label = "query:Query1:0"),
+          DeferredFragmentIdentifier(path = listOf("computers", 1), label = "query:Query1:0"),
+          DeferredFragmentIdentifier(path = listOf("computers", 1, "screen"), label = "fragment:ComputerFields:0"),
+      ), deferredJsonMerger.mergedFragmentIds)
+  }
+
+    @Test
+    fun mergeJsonMultipleIncrementalItems() {
+        val deferredJsonMerger = DeferredJsonMerger()
+
+        val payload1 = """
+      {
+        "data": {
+          "computers": [
+            {
+              "id": "Computer1",
+              "screen": {
+                "isTouch": true
+              }
+            },
+            {
+              "id": "Computer2",
+              "screen": {
+                "isTouch": false
+              }
+            }
+          ]
+        },
+        "hasNext": true
+      }
+    """
+        deferredJsonMerger.merge(payload1.buffer())
+        assertEquals(jsonToMap(payload1), deferredJsonMerger.merged)
+        assertEquals(setOf(), deferredJsonMerger.mergedFragmentIds)
+
+
+        val payload2_3 = """
+    {
+      "incremental": [
+        {
+          "data": {
+            "cpu": "386",
+            "year": 1993,
+            "screen": {
+              "resolution": "640x480"
+            }
+          },
+          "path": [
+            "computers",
+            0
+          ],
+          "label": "query:Query1:0",
+          "extensions": {
+            "duration": {
+              "amount": 100,
+              "unit": "ms"
+            }
+          }
+        },
+        {
+          "data": {
+            "cpu": "486",
+            "year": 1996,
+            "screen": {
+              "resolution": "640x480"
+            }
+          },
+          "path": [
+            "computers",
+            1
+          ],
+          "label": "query:Query1:0",
+          "extensions": {
+            "duration": {
+              "amount": 25,
+              "unit": "ms"
+            }
           }
         }
+      ],
+      "hasNext": true
+    }
+    """
+        val mergedPayloads_1_2_3 = """
+      {
+        "data": {
+          "computers": [
+            {
+              "id": "Computer1",
+              "cpu": "386",
+              "year": 1993,
+              "screen": {
+                "isTouch": true,
+                "resolution": "640x480"
+              }
+            },
+            {
+              "id": "Computer2",
+              "cpu": "486",
+              "year": 1996,
+              "screen": {
+                "isTouch": false,
+                "resolution": "640x480"
+              }
+            }
+          ]
+        },
+        "hasNext": true,
+        "extensions": {
+          "incremental": [
+            {
+              "duration": {
+                "amount": 100,
+                "unit": "ms"
+              }
+            },
+            {
+              "duration": {
+                "amount": 25,
+                "unit": "ms"
+              }
+            }
+          ]
+        }
       }
     """
-    val mergedPayloads_1_2_3_4_5 = """
+        deferredJsonMerger.merge(payload2_3.buffer())
+        assertEquals(jsonToMap(mergedPayloads_1_2_3), deferredJsonMerger.merged)
+        assertEquals(setOf(
+            DeferredFragmentIdentifier(path = listOf("computers", 0), label = "query:Query1:0"),
+            DeferredFragmentIdentifier(path = listOf("computers", 1), label = "query:Query1:0"),
+        ), deferredJsonMerger.mergedFragmentIds)
+
+
+        val payload4_5 = """
+      {
+        "incremental": [
+          {
+            "data": null,
+            "path": [
+              "computers",
+              0,
+              "screen"
+            ],
+            "errors": [
+              {
+                "message": "Cannot resolve isColor",
+                "locations": [
+                  {
+                    "line": 12,
+                    "column": 11
+                  }
+                ],
+                "path": [
+                  "computers",
+                  0,
+                  "screen",
+                  "isColor"
+                ]
+              }
+            ],
+            "label": "fragment:ComputerFields:0"
+          },
+          {
+            "data": {
+              "isColor": false
+            },
+            "path": [
+              "computers",
+              1,
+              "screen"
+            ],
+            "errors": [
+              {
+                "message": "Another error",
+                "locations": [
+                  {
+                    "line": 1,
+                    "column": 1
+                  }
+                ]
+              }
+            ],
+            "label": "fragment:ComputerFields:0",
+            "extensions": {
+              "value": 42,
+              "duration": {
+                "amount": 130,
+                "unit": "ms"
+              }
+            }
+          }
+        ],
+        "hasNext": true
+      }
+    """
+        val mergedPayloads_1_2_3_4_5 = """
       {
         "data": {
           "computers": [
@@ -305,13 +578,32 @@ class DeferJsonMergerTest {
         },
         "hasNext": true,
         "extensions": {
-          "value": 42,
-          "duration": {
-            "amount": 130,
-            "unit": "ms"
-          }
+          "incremental": [
+            {
+              "value": 42,
+              "duration": {
+                "amount": 130,
+                "unit": "ms"
+              }
+            }
+          ]
         },
         "errors": [
+          {
+            "message": "Cannot resolve isColor",
+            "locations": [
+              {
+                "line": 12,
+                "column": 11
+              }
+            ],
+            "path": [
+              "computers",
+              0,
+              "screen",
+              "isColor"
+            ]
+          },
           {
             "message": "Another error",
             "locations": [
@@ -324,14 +616,14 @@ class DeferJsonMergerTest {
         ]
       }
     """
-    deferredJsonMerger.merge(payload5.buffer())
-    assertEquals(jsonToMap(mergedPayloads_1_2_3_4_5), deferredJsonMerger.merged)
-    assertEquals(setOf(
-        DeferredFragmentIdentifier(path = listOf("computers", 0), label = "query:Query1:0"),
-        DeferredFragmentIdentifier(path = listOf("computers", 1), label = "query:Query1:0"),
-        DeferredFragmentIdentifier(path = listOf("computers", 1, "screen"), label = "fragment:ComputerFields:0"),
-    ), deferredJsonMerger.mergedFragmentIds)
-  }
+        deferredJsonMerger.merge(payload4_5.buffer())
+        assertEquals(jsonToMap(mergedPayloads_1_2_3_4_5), deferredJsonMerger.merged)
+        assertEquals(setOf(
+            DeferredFragmentIdentifier(path = listOf("computers", 0), label = "query:Query1:0"),
+            DeferredFragmentIdentifier(path = listOf("computers", 1), label = "query:Query1:0"),
+            DeferredFragmentIdentifier(path = listOf("computers", 1, "screen"), label = "fragment:ComputerFields:0"),
+        ), deferredJsonMerger.mergedFragmentIds)
+    }
 }
 
 private fun String.buffer() = Buffer().writeUtf8(this)
diff --git a/apollo-testing-support/src/appleMain/kotlin/com/apollographql/apollo3/testing/internal/runBlockingOrPromise.kt b/apollo-testing-support/src/appleMain/kotlin/com/apollographql/apollo3/testing/internal/runBlockingOrPromise.kt
deleted file mode 100644
index f56af56f5d..0000000000
--- a/apollo-testing-support/src/appleMain/kotlin/com/apollographql/apollo3/testing/internal/runBlockingOrPromise.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.apollographql.apollo3.testing.internal
-
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.runBlocking
-import kotlin.coroutines.CoroutineContext
-
-internal actual fun runBlockingOrPromise(
-    context: CoroutineContext,
-    block: suspend CoroutineScope.() -> Unit,
-) = runBlocking(context, block)
diff --git a/apollo-testing-support/src/appleMain/kotlin/com/apollographql/apollo3/testing/internal/runTest.kt b/apollo-testing-support/src/appleMain/kotlin/com/apollographql/apollo3/testing/internal/runTest.kt
new file mode 100644
index 0000000000..269940e04d
--- /dev/null
+++ b/apollo-testing-support/src/appleMain/kotlin/com/apollographql/apollo3/testing/internal/runTest.kt
@@ -0,0 +1,37 @@
+package com.apollographql.apollo3.testing.internal
+
+import com.apollographql.apollo3.annotations.ApolloInternal
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.runBlocking
+import kotlin.coroutines.CoroutineContext
+
+@ApolloInternal
+@OptIn(ExperimentalCoroutinesApi::class)
+actual fun runTest(
+    skipDelays: Boolean,
+    context: CoroutineContext,
+    before: suspend CoroutineScope.() -> Unit,
+    after: suspend CoroutineScope.() -> Unit,
+    block: suspend CoroutineScope.() -> Unit,
+) {
+  if (skipDelays) {
+    kotlinx.coroutines.test.runTest(context) {
+      before()
+      try {
+        block()
+      } finally {
+        after()
+      }
+    }
+  } else {
+    runBlocking(context) {
+      before()
+      try {
+        block()
+      } finally {
+        after()
+      }
+    }
+  }
+}
diff --git a/apollo-testing-support/src/commonMain/kotlin/com/apollographql/apollo3/testing/internal/runTest.kt b/apollo-testing-support/src/commonMain/kotlin/com/apollographql/apollo3/testing/internal/runTest.kt
index cec4125b39..523b0ef272 100644
--- a/apollo-testing-support/src/commonMain/kotlin/com/apollographql/apollo3/testing/internal/runTest.kt
+++ b/apollo-testing-support/src/commonMain/kotlin/com/apollographql/apollo3/testing/internal/runTest.kt
@@ -2,7 +2,6 @@ package com.apollographql.apollo3.testing.internal
 
 import com.apollographql.apollo3.annotations.ApolloInternal
 import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlin.coroutines.CoroutineContext
 import kotlin.coroutines.EmptyCoroutineContext
 
@@ -12,36 +11,10 @@ import kotlin.coroutines.EmptyCoroutineContext
  * When [skipDelays] is `true`, the block is executed in [kotlinx.coroutines.test.runTest], otherwise in `runBlocking`.
  */
 @ApolloInternal
-@OptIn(ExperimentalCoroutinesApi::class)
-fun runTest(
+expect fun runTest(
     skipDelays: Boolean = false,
     context: CoroutineContext = EmptyCoroutineContext,
     before: suspend CoroutineScope.() -> Unit = {},
     after: suspend CoroutineScope.() -> Unit = {},
     block: suspend CoroutineScope.() -> Unit,
-) {
-  if (skipDelays) {
-    kotlinx.coroutines.test.runTest(context) {
-      before()
-      try {
-        block()
-      } finally {
-        after()
-      }
-    }
-  } else {
-    runBlockingOrPromise(context) {
-      before()
-      try {
-        block()
-      } finally {
-        after()
-      }
-    }
-  }
-}
-
-internal expect fun runBlockingOrPromise(
-    context: CoroutineContext = EmptyCoroutineContext,
-    block: suspend CoroutineScope.() -> Unit,
 )
diff --git a/apollo-testing-support/src/jsMain/kotlin/com/apollographql/apollo3/testing/internal/runBlockingOrPromise.kt b/apollo-testing-support/src/jsMain/kotlin/com/apollographql/apollo3/testing/internal/runBlockingOrPromise.kt
deleted file mode 100644
index 47aafc78a5..0000000000
--- a/apollo-testing-support/src/jsMain/kotlin/com/apollographql/apollo3/testing/internal/runBlockingOrPromise.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.apollographql.apollo3.testing.internal
-
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.DelicateCoroutinesApi
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.promise
-import kotlin.coroutines.CoroutineContext
-
-@OptIn(DelicateCoroutinesApi::class)
-internal actual fun runBlockingOrPromise(
-    context: CoroutineContext,
-    block: suspend CoroutineScope.() -> Unit,
-): dynamic = GlobalScope.promise(context = context, block = block)
diff --git a/apollo-testing-support/src/jsMain/kotlin/com/apollographql/apollo3/testing/internal/runTest.kt b/apollo-testing-support/src/jsMain/kotlin/com/apollographql/apollo3/testing/internal/runTest.kt
new file mode 100644
index 0000000000..68683a2288
--- /dev/null
+++ b/apollo-testing-support/src/jsMain/kotlin/com/apollographql/apollo3/testing/internal/runTest.kt
@@ -0,0 +1,39 @@
+package com.apollographql.apollo3.testing.internal
+
+import com.apollographql.apollo3.annotations.ApolloInternal
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.DelicateCoroutinesApi
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.promise
+import kotlin.coroutines.CoroutineContext
+
+@ApolloInternal
+@OptIn(ExperimentalCoroutinesApi::class, DelicateCoroutinesApi::class)
+actual fun runTest(
+    skipDelays: Boolean,
+    context: CoroutineContext,
+    before: suspend CoroutineScope.() -> Unit,
+    after: suspend CoroutineScope.() -> Unit,
+    block: suspend CoroutineScope.() -> Unit,
+): dynamic {
+  return if (skipDelays) {
+    kotlinx.coroutines.test.runTest(context) {
+      before()
+      try {
+        block()
+      } finally {
+        after()
+      }
+    }
+  } else {
+    GlobalScope.promise(context = context) {
+      before()
+      try {
+        block()
+      } finally {
+        after()
+      }
+    }
+  }
+}
diff --git a/apollo-testing-support/src/jvmMain/kotlin/com/apollographql/apollo3/testing/internal/runBlockingOrPromise.kt b/apollo-testing-support/src/jvmMain/kotlin/com/apollographql/apollo3/testing/internal/runBlockingOrPromise.kt
deleted file mode 100644
index f56af56f5d..0000000000
--- a/apollo-testing-support/src/jvmMain/kotlin/com/apollographql/apollo3/testing/internal/runBlockingOrPromise.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.apollographql.apollo3.testing.internal
-
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.runBlocking
-import kotlin.coroutines.CoroutineContext
-
-internal actual fun runBlockingOrPromise(
-    context: CoroutineContext,
-    block: suspend CoroutineScope.() -> Unit,
-) = runBlocking(context, block)
diff --git a/apollo-testing-support/src/jvmMain/kotlin/com/apollographql/apollo3/testing/internal/runTest.kt b/apollo-testing-support/src/jvmMain/kotlin/com/apollographql/apollo3/testing/internal/runTest.kt
new file mode 100644
index 0000000000..269940e04d
--- /dev/null
+++ b/apollo-testing-support/src/jvmMain/kotlin/com/apollographql/apollo3/testing/internal/runTest.kt
@@ -0,0 +1,37 @@
+package com.apollographql.apollo3.testing.internal
+
+import com.apollographql.apollo3.annotations.ApolloInternal
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.runBlocking
+import kotlin.coroutines.CoroutineContext
+
+@ApolloInternal
+@OptIn(ExperimentalCoroutinesApi::class)
+actual fun runTest(
+    skipDelays: Boolean,
+    context: CoroutineContext,
+    before: suspend CoroutineScope.() -> Unit,
+    after: suspend CoroutineScope.() -> Unit,
+    block: suspend CoroutineScope.() -> Unit,
+) {
+  if (skipDelays) {
+    kotlinx.coroutines.test.runTest(context) {
+      before()
+      try {
+        block()
+      } finally {
+        after()
+      }
+    }
+  } else {
+    runBlocking(context) {
+      before()
+      try {
+        block()
+      } finally {
+        after()
+      }
+    }
+  }
+}
diff --git a/tests/data-builders-java/build.gradle.kts b/tests/data-builders-java/build.gradle.kts
new file mode 100644
index 0000000000..9208a6f27e
--- /dev/null
+++ b/tests/data-builders-java/build.gradle.kts
@@ -0,0 +1,24 @@
+plugins {
+  id("com.apollographql.apollo3")
+  id("java")
+  id("apollo.test")
+}
+
+dependencies {
+  implementation("com.apollographql.apollo3:apollo-runtime")
+  testImplementation(libs.junit)
+}
+
+apollo {
+  packageName.set("data.builders")
+  generateDataBuilders.set(true)
+  generateKotlinModels.set(false)
+  addTypename.set("always")
+  mapScalar("Long1", "data.builders.MyLong", "data.builders.MyLong.MyLongAdapter.INSTANCE")
+  mapScalar("Long2", "data.builders.MyLong")
+}
+
+java {
+    sourceCompatibility = JavaVersion.VERSION_1_8
+    targetCompatibility = JavaVersion.VERSION_1_8
+}
\ No newline at end of file
diff --git a/tests/data-builders/src/main/graphql/operations.graphql b/tests/data-builders-java/src/main/graphql/operations.graphql
similarity index 100%
rename from tests/data-builders/src/main/graphql/operations.graphql
rename to tests/data-builders-java/src/main/graphql/operations.graphql
diff --git a/tests/data-builders/src/main/graphql/schema.graphqls b/tests/data-builders-java/src/main/graphql/schema.graphqls
similarity index 100%
rename from tests/data-builders/src/main/graphql/schema.graphqls
rename to tests/data-builders-java/src/main/graphql/schema.graphqls
diff --git a/tests/data-builders-java/src/main/java/data/builders/MyLong.java b/tests/data-builders-java/src/main/java/data/builders/MyLong.java
new file mode 100644
index 0000000000..9a7d712779
--- /dev/null
+++ b/tests/data-builders-java/src/main/java/data/builders/MyLong.java
@@ -0,0 +1,39 @@
+package data.builders;
+
+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 org.jetbrains.annotations.NotNull;
+
+import java.io.IOException;
+
+public class MyLong {
+  public Long value;
+
+  public MyLong(Long value) {
+    this.value = value;
+  }
+
+  public static class MyLongAdapter implements Adapter<MyLong> {
+    @Override public MyLong fromJson(@NotNull JsonReader reader, @NotNull CustomScalarAdapters customScalarAdapters)  {
+      try {
+        return new MyLong(reader.nextLong());
+      } catch (Exception e) {
+        throw new RuntimeException();
+      }
+    }
+
+    @Override public void toJson(@NotNull JsonWriter writer, @NotNull CustomScalarAdapters customScalarAdapters, MyLong value) {
+      try {
+        writer.value(value.value);
+      } catch (Exception e) {
+        throw new RuntimeException();
+      }
+    }
+
+    public static final MyLongAdapter INSTANCE = new MyLongAdapter();
+  }
+}
+
+
diff --git a/tests/data-builders-java/src/test/java/test/DataBuilderTest.java b/tests/data-builders-java/src/test/java/test/DataBuilderTest.java
new file mode 100644
index 0000000000..63fdf34641
--- /dev/null
+++ b/tests/data-builders-java/src/test/java/test/DataBuilderTest.java
@@ -0,0 +1,242 @@
+package test;
+
+import com.apollographql.apollo3.api.FakeResolver;
+import com.apollographql.apollo3.api.FakeResolverContext;
+import data.builders.GetAliasesQuery;
+import data.builders.GetAnimalQuery;
+import data.builders.GetCustomScalarQuery;
+import data.builders.GetDirectionQuery;
+import data.builders.GetEverythingQuery;
+import data.builders.GetFelineQuery;
+import data.builders.GetIntQuery;
+import data.builders.GetPartialQuery;
+import data.builders.PutIntMutation;
+import data.builders.type.Direction;
+import data.builders.type.builder.BuilderFactory;
+import data.builders.MyLong;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+
+public class DataBuilderTest {
+  private BuilderFactory factory = BuilderFactory.DEFAULT;
+
+  @Test
+  public void nullabilityTest() {
+    GetIntQuery.Data data = GetIntQuery.buildData(
+        factory.buildQuery()
+            .nullableInt(null)
+            .nonNullableInt(42)
+            .build()
+    );
+
+    assertEquals(null, data.nullableInt);
+    assertEquals(Integer.valueOf(42), data.nonNullableInt);
+  }
+
+  @Test
+  public void aliasTest() {
+    GetAliasesQuery.Data data = GetAliasesQuery.buildData(
+        factory.buildQuery()
+            .cat(factory.buildCat().species("Cat").build())
+            .alias("aliasedNullableInt", 50)
+            .alias(
+                "aliasedCat",
+                factory.buildCat().species("AliasedCat").build()
+            )
+            .build()
+    );
+
+    assertEquals(Integer.valueOf(50), data.aliasedNullableInt);
+    assertEquals("Cat", data.cat.species);
+    assertEquals("AliasedCat", data.aliasedCat.species);
+  }
+
+  @Test
+  public void mutationTest() {
+    PutIntMutation.Data data = PutIntMutation.buildData(
+        factory.buildMutationRoot()
+            .nullableInt(null)
+            .build()
+    );
+
+    assertEquals(null, data.nullableInt);
+  }
+
+  @Test
+  public void interfaceTest() {
+    GetAnimalQuery.Data data = GetAnimalQuery.buildData(
+        factory.buildQuery()
+            .animal(
+                factory.buildLion()
+                    .species("LionSpecies")
+                    .roar("Rooooaaarr")
+                    .build()
+            )
+            .build()
+    );
+
+    assertEquals("Lion", data.animal.__typename);
+    assertEquals("LionSpecies", data.animal.species);
+    assertEquals("Rooooaaarr", data.animal.onLion.roar);
+  }
+
+  @Test
+  public void unionTest1() {
+    GetFelineQuery.Data data = GetFelineQuery.buildData(
+        factory.buildQuery()
+            .feline(
+                factory.buildLion()
+                    .species("LionSpecies")
+                    .roar("Rooooaaarr")
+                    .build()
+            )
+            .build()
+    );
+
+    assertEquals("Lion", data.feline.__typename);
+    assertEquals(null, data.feline.onCat);
+  }
+
+  @Test
+  public void unionTest2() {
+    GetFelineQuery.Data data = GetFelineQuery.buildData(
+        factory.buildQuery()
+            .feline(
+                factory.buildCat()
+                    .species("CatSpecies")
+                    .mustaches(5)
+                    .build()
+            )
+            .build()
+    );
+
+    assertEquals("Cat", data.feline.__typename);
+    assertEquals(Integer.valueOf(5), data.feline.onCat.mustaches);
+  }
+
+  @Test
+  public void enumTest() {
+    GetDirectionQuery.Data data = GetDirectionQuery.buildData(
+        factory.buildQuery()
+            .direction(Direction.NORTH)
+            .build()
+    );
+    assertEquals(Direction.NORTH, data.direction);
+  }
+
+  @Test
+  public void customScalarTest() {
+    GetCustomScalarQuery.Data data = GetCustomScalarQuery.buildData(
+        factory.buildQuery()
+            .long1(new MyLong(42L))
+            .long2(new MyLong(43L))
+            .long3(44)
+            .listOfListOfLong1(Collections.singletonList(Collections.singletonList(new MyLong(42L))))
+            .build()
+    );
+
+
+    assertEquals(Long.valueOf(42), data.long1.value);
+    assertEquals(Long.valueOf(43), data.long2.value);
+    assertEquals(44, data.long3);
+  }
+
+  @Test
+  public void fakeValues() {
+    GetEverythingQuery.Data data = GetEverythingQuery.buildData(factory.buildQuery().build());
+
+    assertEquals(Direction.SOUTH, data.direction);
+    assertEquals(Integer.valueOf(0), data.nullableInt);
+    assertEquals(Integer.valueOf(1), data.nonNullableInt);
+    assertEquals(Arrays.asList(
+        Arrays.asList(2, 3, 4),
+        Arrays.asList(5, 6, 7),
+        Arrays.asList(8, 9, 10)
+    ), data.listOfListOfInt);
+    assertEquals(Integer.valueOf(11), data.cat.mustaches);
+    assertEquals("Lion", data.animal.__typename);
+    assertEquals("Cat", data.feline.__typename);
+  }
+
+  @Test
+  public void partialFakeValues() {
+    GetPartialQuery.Data data = GetPartialQuery.buildData(
+        factory.buildQuery()
+            .listOfListOfAnimal(
+                Collections.singletonList(
+                    Collections.singletonList(
+                        factory.buildLion()
+                            .species("FooSpecies")
+                            .build()
+                    )
+                )
+            )
+            .build()
+      );
+
+
+    assertEquals(
+        new GetPartialQuery.Data(
+            Collections.singletonList(
+                Collections.singletonList (
+                    new GetPartialQuery.ListOfListOfAnimal(
+                        "Lion",
+                        "FooSpecies",
+                        new GetPartialQuery.OnLion("roar")
+                    )
+                )
+            )
+        ),
+        data
+    );
+  }
+
+  static class MyFakeResolver implements FakeResolver {
+    @NotNull @Override public Object resolveLeaf(@NotNull FakeResolverContext context) {
+      String name = context.getMergedField().getType().leafType().getName();
+      Object ret = null;
+      switch (name) {
+        case "Long1": {
+          ret = "45";
+          break;
+        }
+        case "Long2": {
+          ret = new MyLong(46L);
+          break;
+        }
+        case "Long3": {
+          ret = 47L;
+          break;
+        }
+        default: throw new IllegalStateException();
+      }
+      return ret;
+    }
+
+    @Override public int resolveListSize(@NotNull FakeResolverContext context) {
+      return 1;
+    }
+
+    @Override public boolean resolveMaybeNull(@NotNull FakeResolverContext context) {
+      return false;
+    }
+
+    @NotNull @Override public String resolveTypename(@NotNull FakeResolverContext context) {
+      throw new IllegalStateException();
+    }
+  }
+
+  @Test
+  public void customScalarFakeValues() {
+    GetCustomScalarQuery.Data data = GetCustomScalarQuery.buildData(factory.buildQuery().build(), new MyFakeResolver());
+
+    assertEquals(Long.valueOf(45L), data.long1.value);
+    assertEquals(Long.valueOf(46L), data.long2.value);
+    assertEquals(47, data.long3); // AnyAdapter will try to fit the smallest possible number
+  }
+}
diff --git a/tests/data-builders/build.gradle.kts b/tests/data-builders-kotlin/build.gradle.kts
similarity index 100%
rename from tests/data-builders/build.gradle.kts
rename to tests/data-builders-kotlin/build.gradle.kts
diff --git a/tests/data-builders-kotlin/src/main/graphql/operations.graphql b/tests/data-builders-kotlin/src/main/graphql/operations.graphql
new file mode 100644
index 0000000000..9c2f2ee4dc
--- /dev/null
+++ b/tests/data-builders-kotlin/src/main/graphql/operations.graphql
@@ -0,0 +1,76 @@
+query GetInt {
+  nullableInt
+  nonNullableInt
+}
+
+query GetCustomScalar {
+  long1
+  long2
+  long3
+  listOfListOfLong1
+}
+
+query GetDirection {
+  direction
+}
+
+mutation PutInt {
+  nullableInt
+}
+
+query GetAliases {
+  aliasedNullableInt: nullableInt
+  cat {
+    species
+  }
+  aliasedCat: cat {
+    species
+  }
+}
+
+query GetAnimal {
+  animal {
+    species
+    ... on Lion {
+      roar
+    }
+  }
+}
+
+query GetFeline {
+  feline {
+    ... on Cat {
+      mustaches
+    }
+  }
+}
+
+query GetEverything {
+  nullableInt
+  nonNullableInt
+  listOfListOfInt
+  direction
+  listOfListOfAnimal {
+    species
+  }
+  cat {
+    mustaches
+  }
+  animal {
+    species
+  }
+  feline {
+    ... on Lion {
+      roar
+    }
+  }
+}
+
+query GetPartial {
+  listOfListOfAnimal {
+    species
+    ... on Lion {
+      roar
+    }
+  }
+}
diff --git a/tests/data-builders-kotlin/src/main/graphql/schema.graphqls b/tests/data-builders-kotlin/src/main/graphql/schema.graphqls
new file mode 100644
index 0000000000..d88c3c729f
--- /dev/null
+++ b/tests/data-builders-kotlin/src/main/graphql/schema.graphqls
@@ -0,0 +1,55 @@
+schema {
+  query: Query
+  mutation: MutationRoot
+}
+
+type Query {
+  nullableInt: Int
+  nonNullableInt: Int!
+  direction: Direction!,
+  cat: Cat!
+  animal: Animal!
+  feline: Feline!
+  long1: Long1
+  listOfListOfLong1: [[Long1]!]
+  long2: Long2
+  long3: Long3
+  listOfListOfInt: [[Int]!]
+  listOfListOfAnimal: [[Animal]!]
+}
+
+enum Direction {
+  SOUTH,
+  NORTH
+}
+
+type MutationRoot {
+  nullableInt: Int
+}
+
+interface Animal {
+  species: String!
+}
+
+type Cat implements Animal & Animal2 {
+  species: String!
+  mustaches: Int!
+}
+
+type Lion implements Animal {
+  species: String!
+  roar: String!
+}
+
+union Feline = Cat | Lion
+
+# an interface that is not directly queried but still needs to be added because the data builders
+# will reference them
+interface Animal2 {
+  species: String!
+}
+union Feline2 = Cat | Lion
+
+scalar Long1
+scalar Long2
+scalar Long3
\ No newline at end of file
diff --git a/tests/data-builders/src/main/kotlin/MyLong.kt b/tests/data-builders-kotlin/src/main/kotlin/MyLong.kt
similarity index 100%
rename from tests/data-builders/src/main/kotlin/MyLong.kt
rename to tests/data-builders-kotlin/src/main/kotlin/MyLong.kt
diff --git a/tests/data-builders/src/test/kotlin/test/DataBuilderTest.kt b/tests/data-builders-kotlin/src/test/kotlin/test/DataBuilderTest.kt
similarity index 100%
rename from tests/data-builders/src/test/kotlin/test/DataBuilderTest.kt
rename to tests/data-builders-kotlin/src/test/kotlin/test/DataBuilderTest.kt
diff --git a/tests/defer/build.gradle.kts b/tests/defer/build.gradle.kts
index 3877bb7aac..7ae10eb41e 100644
--- a/tests/defer/build.gradle.kts
+++ b/tests/defer/build.gradle.kts
@@ -33,7 +33,7 @@ kotlin {
 
     val jsTest by getting {
       dependencies {
-        implementation(npm("graphql-helix", "1.12.0"))
+        implementation(npm("graphql-helix", "1.13.0"))
         implementation(npm("express", "4.17.3"))
         implementation(npm("ws", "8.2.2"))
         implementation(npm("graphql-ws", "5.5.0"))
diff --git a/tests/defer/src/commonMain/graphql/operation.graphql b/tests/defer/src/commonMain/graphql/operation.graphql
index 1e5a09cf5e..a8f3dfb722 100644
--- a/tests/defer/src/commonMain/graphql/operation.graphql
+++ b/tests/defer/src/commonMain/graphql/operation.graphql
@@ -1,7 +1,7 @@
 query WithFragmentSpreadsQuery {
   computers {
     id
-    ...ComputerFields @experimental_defer
+    ...ComputerFields @defer
   }
 }
 
@@ -10,7 +10,7 @@ fragment ComputerFields on Computer {
   year
   screen {
     resolution
-    ...ScreenFields @experimental_defer(label: "a")
+    ...ScreenFields @defer(label: "a")
   }
 }
 
@@ -22,12 +22,12 @@ fragment ScreenFields on Screen {
 query WithInlineFragmentsQuery {
   computers {
     id
-    ... on Computer @experimental_defer {
+    ... on Computer @defer {
       cpu
       year
       screen {
         resolution
-        ... on Screen @experimental_defer(label: "b") {
+        ... on Screen @defer(label: "b") {
           isColor
         }
       }
@@ -39,14 +39,14 @@ query WithInlineFragmentsQuery {
 mutation WithFragmentSpreadsMutation {
   computers {
     id
-    ...ComputerFields @experimental_defer(label: "c")
+    ...ComputerFields @defer(label: "c")
   }
 }
 
 subscription WithInlineFragmentsSubscription {
   count(to: 3) {
     value
-    ... on Counter @experimental_defer {
+    ... on Counter @defer {
       valueTimesTwo
     }
   }
@@ -55,7 +55,7 @@ subscription WithInlineFragmentsSubscription {
 subscription WithFragmentSpreadsSubscription {
   count(to: 3) {
     value
-    ...CounterFields @experimental_defer(label: "d")
+    ...CounterFields @defer(label: "d")
   }
 }
 
diff --git a/tests/defer/src/commonTest/kotlin/test/DeferNormalizedCacheTest.kt b/tests/defer/src/commonTest/kotlin/test/DeferNormalizedCacheTest.kt
index 419417e6a7..d07d464e13 100644
--- a/tests/defer/src/commonTest/kotlin/test/DeferNormalizedCacheTest.kt
+++ b/tests/defer/src/commonTest/kotlin/test/DeferNormalizedCacheTest.kt
@@ -66,8 +66,8 @@ class DeferNormalizedCacheTest {
     // Fill the cache by doing a network only request
     val jsonList = listOf(
         """{"data":{"computers":[{"__typename":"Computer","id":"Computer1"}]},"hasNext":true}""",
-        """{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0],"hasNext":true}""",
-        """{"data":{"isColor":false},"path":["computers",0,"screen"],"hasNext":false,"label":"a"}""",
+        """{"incremental": [{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0]}],"hasNext":true}""",
+        """{"incremental": [{"data":{"isColor":false},"path":["computers",0,"screen"],"label":"a"}],"hasNext":false}""",
     )
     mockServer.enqueueMultipart(jsonList)
     apolloClient.query(WithFragmentSpreadsQuery()).fetchPolicy(FetchPolicy.NetworkOnly).toFlow().collect()
@@ -93,8 +93,8 @@ class DeferNormalizedCacheTest {
     // Fill the cache by doing a first request
     val jsonList = listOf(
         """{"data":{"computers":[{"__typename":"Computer","id":"Computer1"}]},"hasNext":true}""",
-        """{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0],"hasNext":true}""",
-        """{"data":{"isColor":false},"path":["computers",0,"screen"],"hasNext":false,"label":"a"}""",
+        """{"incremental": [{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0]}],"hasNext":true}""",
+        """{"incremental": [{"data":{"isColor":false},"path":["computers",0,"screen"],"label":"a"}],"hasNext":false}""",
     )
     mockServer.enqueueMultipart(jsonList)
     apolloClient.query(WithFragmentSpreadsQuery()).fetchPolicy(FetchPolicy.NetworkOnly).toFlow().collect()
@@ -128,8 +128,8 @@ class DeferNormalizedCacheTest {
 
     val jsonList = listOf(
         """{"data":{"computers":[{"__typename":"Computer","id":"Computer1"}]},"hasNext":true}""",
-        """{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0],"hasNext":true}""",
-        """{"data":{"isColor":false},"path":["computers",0,"screen"],"hasNext":false,"label":"a"}""",
+        """{"incremental": [{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0]}],"hasNext":true}""",
+        """{"incremental": [{"data":{"isColor":false},"path":["computers",0,"screen"],"label":"a"}],"hasNext":false}""",
     )
     mockServer.enqueueMultipart(jsonList)
 
@@ -168,8 +168,8 @@ class DeferNormalizedCacheTest {
 
     val jsonList = listOf(
         """{"data":{"computers":[{"__typename":"Computer","id":"Computer1"}]},"hasNext":true}""",
-        """{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0],"hasNext":true}""",
-        """{"data":{"isColor":false},"path":["computers",0,"screen"],"hasNext":false,"label":"a"}""",
+        """{"incremental": [{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0]}],"hasNext":true}""",
+        """{"incremental": [{"data":{"isColor":false},"path":["computers",0,"screen"],"label":"a"}],"hasNext":false}""",
     )
     mockServer.enqueueMultipart(jsonList)
 
@@ -208,8 +208,8 @@ class DeferNormalizedCacheTest {
 
     val jsonList1 = listOf(
         """{"data":{"computers":[{"__typename":"Computer","id":"Computer1"}]},"hasNext":true}""",
-        """{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0],"hasNext":true}""",
-        """{"data":{"isColor":false},"path":["computers",0,"screen"],"hasNext":false,"label":"a"}""",
+        """{"incremental": [{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0]}],"hasNext":true}""",
+        """{"incremental": [{"data":{"isColor":false},"path":["computers",0,"screen"],"label":"a"}],"hasNext":false}""",
     )
     mockServer.enqueueMultipart(jsonList1)
 
@@ -235,8 +235,8 @@ class DeferNormalizedCacheTest {
 
     val jsonList2 = listOf(
         """{"data":{"computers":[{"__typename":"Computer","id":"Computer2"}]},"hasNext":true}""",
-        """{"data":{"cpu":"486","year":1996,"screen":{"__typename":"Screen","resolution":"800x600"}},"path":["computers",0],"hasNext":true}""",
-        """{"data":{"isColor":true},"path":["computers",0,"screen"],"hasNext":false,"label":"a"}""",
+        """{"incremental": [{"data":{"cpu":"486","year":1996,"screen":{"__typename":"Screen","resolution":"800x600"}},"path":["computers",0]}],"hasNext":true}""",
+        """{"incremental": [{"data":{"isColor":true},"path":["computers",0,"screen"],"label":"a"}],"hasNext":false}""",
     )
     mockServer.enqueueMultipart(jsonList2)
 
@@ -271,8 +271,8 @@ class DeferNormalizedCacheTest {
 
     val jsonList = listOf(
         """{"data":{"computers":[{"__typename":"Computer","id":"Computer1"}]},"hasNext":true}""",
-        """{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0],"hasNext":true}""",
-        """{"data":null,"path":["computers",0,"screen"],"label":"b","errors":[{"message":"Cannot resolve isColor","locations":[{"line":1,"column":119}],"path":["computers",0,"screen","isColor"]}],"hasNext":false}""",
+        """{"incremental": [{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0]}],"hasNext":true}""",
+        """{"incremental": [{"data":null,"path":["computers",0,"screen"],"label":"b","errors":[{"message":"Cannot resolve isColor","locations":[{"line":1,"column":119}],"path":["computers",0,"screen","isColor"]}]}],"hasNext":false}""",
     )
     mockServer.enqueueMultipart(jsonList)
 
@@ -402,8 +402,8 @@ class DeferNormalizedCacheTest {
   fun mutation() = runTest(before = { setUp() }, after = { tearDown() }) {
     val jsonList = listOf(
         """{"data":{"computers":[{"__typename":"Computer","id":"Computer1"}]},"hasNext":true}""",
-        """{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0],"hasNext":true,"label":"c"}""",
-        """{"data":{"isColor":false},"path":["computers",0,"screen"],"hasNext":false,"label":"a"}""",
+        """{"incremental": [{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0],"label":"c"}],"hasNext":true}""",
+        """{"incremental": [{"data":{"isColor":false},"path":["computers",0,"screen"],"label":"a"}],"hasNext":false}""",
     )
     mockServer.enqueueMultipart(jsonList)
     val networkActual = apolloClient.mutation(WithFragmentSpreadsMutation()).toFlow().toList().map { it.dataAssertNoErrors }
@@ -441,8 +441,8 @@ class DeferNormalizedCacheTest {
   fun mutationWithOptimisticDataFails() = runTest(before = { setUp() }, after = { tearDown() }) {
     val jsonList = listOf(
         """{"data":{"computers":[{"__typename":"Computer","id":"Computer1"}]},"hasNext":true}""",
-        """{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0],"hasNext":true,"label":"c"}""",
-        """{"data":{"isColor":false},"path":["computers",0,"screen"],"hasNext":false,"label":"a"}""",
+        """{"incremental": [{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0],"label":"c"}],"hasNext":true}""",
+        """{"incremental": [{"data":{"isColor":false},"path":["computers",0,"screen"],"label":"a"}],"hasNext":false}""",
     )
     mockServer.enqueueMultipart(jsonList)
     val responses = apolloClient.mutation(WithFragmentSpreadsMutation()).optimisticUpdates(
diff --git a/tests/defer/src/commonTest/kotlin/test/DeferTest.kt b/tests/defer/src/commonTest/kotlin/test/DeferTest.kt
index 047568d029..069e01ff62 100644
--- a/tests/defer/src/commonTest/kotlin/test/DeferTest.kt
+++ b/tests/defer/src/commonTest/kotlin/test/DeferTest.kt
@@ -42,10 +42,10 @@ class DeferTest {
   fun deferWithFragmentSpreads() = runTest(before = { setUp() }, after = { tearDown() }) {
     val jsonList = listOf(
         """{"data":{"computers":[{"__typename":"Computer","id":"Computer1"},{"__typename":"Computer","id":"Computer2"}]},"hasNext":true}""",
-        """{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0],"hasNext":true}""",
-        """{"data":{"cpu":"486","year":1996,"screen":{"__typename":"Screen","resolution":"800x600"}},"path":["computers",1],"hasNext":true}""",
-        """{"data":{"isColor":false},"path":["computers",0,"screen"],"hasNext":true,"label":"a"}""",
-        """{"data":{"isColor":true},"path":["computers",1,"screen"],"hasNext":false,"label":"a"}""",
+        """{"incremental": [{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0]}],"hasNext":true}""",
+        """{"incremental": [{"data":{"cpu":"486","year":1996,"screen":{"__typename":"Screen","resolution":"800x600"}},"path":["computers",1]}],"hasNext":true}""",
+        """{"incremental": [{"data":{"isColor":false},"path":["computers",0,"screen"],"label":"a"}],"hasNext":true}""",
+        """{"incremental": [{"data":{"isColor":true},"path":["computers",1,"screen"],"label":"a"}],"hasNext":false}""",
     )
 
     val expectedDataList = listOf(
@@ -100,10 +100,10 @@ class DeferTest {
   fun deferWithInlineFragments() = runTest(before = { setUp() }, after = { tearDown() }) {
     val jsonList = listOf(
         """{"data":{"computers":[{"__typename":"Computer","id":"Computer1"},{"__typename":"Computer","id":"Computer2"}]},"hasNext":true}""",
-        """{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0],"hasNext":true}""",
-        """{"data":{"cpu":"486","year":1996,"screen":{"__typename":"Screen","resolution":"800x600"}},"path":["computers",1],"hasNext":true}""",
-        """{"data":{"isColor":false},"path":["computers",0,"screen"],"hasNext":true,"label":"b"}""",
-        """{"data":{"isColor":true},"path":["computers",1,"screen"],"hasNext":false,"label":"b"}""",
+        """{"incremental": [{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0]}],"hasNext":true}""",
+        """{"incremental": [{"data":{"cpu":"486","year":1996,"screen":{"__typename":"Screen","resolution":"800x600"}},"path":["computers",1]}],"hasNext":true}""",
+        """{"incremental": [{"data":{"isColor":false},"path":["computers",0,"screen"],"label":"b"}],"hasNext":true}""",
+        """{"incremental": [{"data":{"isColor":true},"path":["computers",1,"screen"],"label":"b"}],"hasNext":false}""",
     )
 
     val expectedDataList = listOf(
@@ -158,10 +158,10 @@ class DeferTest {
   fun deferWithFragmentSpreadsAndError() = runTest(before = { setUp() }, after = { tearDown() }) {
     val jsonList = listOf(
         """{"data":{"computers":[{"__typename":"Computer","id":"Computer1"},{"__typename":"Computer","id":"Computer2"}]},"hasNext":true}""",
-        """{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0],"hasNext":true}""",
-        """{"data":null,"path":["computers",0,"screen"],"label":"b","errors":[{"message":"Cannot resolve isColor","locations":[{"line":1,"column":119}],"path":["computers",0,"screen","isColor"]}],"hasNext":true}""",
-        """{"data":{"cpu":"486","year":1996,"screen":{"__typename":"Screen","resolution":"800x600"}},"path":["computers",1],"hasNext":true}""",
-        """{"data":{"isColor":true},"path":["computers",1,"screen"],"hasNext":false,"label":"a"}""",
+        """{"incremental": [{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0]}],"hasNext":true}""",
+        """{"incremental": [{"data":null,"path":["computers",0,"screen"],"label":"b","errors":[{"message":"Cannot resolve isColor","locations":[{"line":1,"column":119}],"path":["computers",0,"screen","isColor"]}]}],"hasNext":true}""",
+        """{"incremental": [{"data":{"cpu":"486","year":1996,"screen":{"__typename":"Screen","resolution":"800x600"}},"path":["computers",1]}],"hasNext":true}""",
+        """{"incremental": [{"data":{"isColor":true},"path":["computers",1,"screen"],"label":"a"}],"hasNext":false}""",
     )
 
     val query = WithFragmentSpreadsQuery()
@@ -266,10 +266,10 @@ class DeferTest {
 
     val jsonList = listOf(
         """{"data":{"computers":[{"__typename":"Computer","id":"Computer1"},{"__typename":"Computer","id":"Computer2"}]},"hasNext":true}""",
-        """{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0],"hasNext":true}""",
-        """{"data":{"cpu":"486","year":1996,"screen":{"__typename":"Screen","resolution":"800x600"}},"path":["computers",1],"hasNext":true}""",
-        """{"data":{"isColor":false},"path":["computers",0,"screen"],"hasNext":true,"label":"a"}""",
-        """{"data":{"isColor":true},"path":["computers",1,"screen"],"hasNext":false,"label":"a"}""",
+        """{"incremental": [{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0]}],"hasNext":true}""",
+        """{"incremental": [{"data":{"cpu":"486","year":1996,"screen":{"__typename":"Screen","resolution":"800x600"}},"path":["computers",1]}],"hasNext":true}""",
+        """{"incremental": [{"data":{"isColor":false},"path":["computers",0,"screen"],"label":"a"}],"hasNext":true}""",
+        """{"incremental": [{"data":{"isColor":true},"path":["computers",1,"screen"],"label":"a"}],"hasNext":false}""",
     )
 
     for ((index, json) in jsonList.withIndex()) {
diff --git a/tests/defer/src/jsTest/kotlin/helix/HelixServer.kt b/tests/defer/src/jsTest/kotlin/helix/HelixServer.kt
index fccb3c38e4..44663a08c3 100644
--- a/tests/defer/src/jsTest/kotlin/helix/HelixServer.kt
+++ b/tests/defer/src/jsTest/kotlin/helix/HelixServer.kt
@@ -35,7 +35,7 @@ class HelixServer(
       if (shouldRenderGraphiQL(request)) {
         res.send(
             renderGraphiQL(dynamicObject {
-              subscriptionsEndpoint = "ws://localhost:4000/graphql"
+              subscriptionsEndpoint = "ws://localhost:$port/graphql"
             })
         )
         return@use null
diff --git a/tests/defer/src/jsTest/kotlin/test/DeferWithHelixTest.kt b/tests/defer/src/jsTest/kotlin/test/DeferWithHelixTest.kt
index da5d17cfbd..9b8fe4c711 100644
--- a/tests/defer/src/jsTest/kotlin/test/DeferWithHelixTest.kt
+++ b/tests/defer/src/jsTest/kotlin/test/DeferWithHelixTest.kt
@@ -26,19 +26,21 @@ import helix.HelixServer
 import kotlinx.coroutines.flow.toList
 import util.dynamicObject
 import util.jsAsyncIterator
+import kotlin.random.Random
 import kotlin.test.Ignore
 import kotlin.test.Test
 import kotlin.test.assertEquals
 
 @Ignore
-// TODO These tests are temporarily ignored while @defer has been renamed to @experimental_defer
-// See https://github.com/apollographql/apollo-kotlin/issues/4071
+// TODO These tests are temporarily ignored as the latest version of graphql-js
+// uses a package format which is incompatible with Kotlin/JS.
+// See https://youtrack.jetbrains.com/issue/KT-12784
 class DeferWithHelixTest {
   private lateinit var helixServer: HelixServer
   private lateinit var apolloClient: ApolloClient
 
   private suspend fun setUp() {
-    helixServer = HelixServer(schema)
+    helixServer = HelixServer(schema, port = Random.nextInt(1024, 65535))
     apolloClient = ApolloClient.Builder()
         .serverUrl(helixServer.url())
         .webSocketServerUrl(helixServer.webSocketUrl())
diff --git a/tests/defer/src/jvmTest/kotlin/test/DeferJvmTest.kt b/tests/defer/src/jvmTest/kotlin/test/DeferJvmTest.kt
index 29e4781a11..6eba9627bf 100644
--- a/tests/defer/src/jvmTest/kotlin/test/DeferJvmTest.kt
+++ b/tests/defer/src/jvmTest/kotlin/test/DeferJvmTest.kt
@@ -52,10 +52,10 @@ class DeferJvmTest {
 
     val jsonList = listOf(
         """{"data":{"computers":[{"__typename":"Computer","id":"Computer1"},{"__typename":"Computer","id":"Computer2"}]},"hasNext":true}""",
-        """{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0],"hasNext":true}""",
-        """{"data":{"cpu":"486","year":1996,"screen":{"__typename":"Screen","resolution":"800x600"}},"path":["computers",1],"hasNext":true}""",
-        """{"data":{"isColor":false},"path":["computers",0,"screen"],"hasNext":true,"label":"a"}""",
-        """{"data":{"isColor":true},"path":["computers",1,"screen"],"hasNext":false,"label":"a"}""",
+        """{"incremental":[{"data":{"cpu":"386","year":1993,"screen":{"__typename":"Screen","resolution":"640x480"}},"path":["computers",0]}],"hasNext":true}""",
+        """{"incremental":[{"data":{"cpu":"486","year":1996,"screen":{"__typename":"Screen","resolution":"800x600"}},"path":["computers",1]}],"hasNext":true}""",
+        """{"incremental":[{"data":{"isColor":false},"path":["computers",0,"screen"],"label":"a"}],"hasNext":true}""",
+        """{"incremental":[{"data":{"isColor":true},"path":["computers",1,"screen"],"label":"a"}],"hasNext":false}""",
     )
 
     for ((index, json) in jsonList.withIndex()) {
diff --git a/tests/integration-tests/src/commonTest/kotlin/test/LoggingInterceptorTest.kt b/tests/integration-tests/src/commonTest/kotlin/test/LoggingInterceptorTest.kt
index 9b4db6bcae..5ae24cad9b 100644
--- a/tests/integration-tests/src/commonTest/kotlin/test/LoggingInterceptorTest.kt
+++ b/tests/integration-tests/src/commonTest/kotlin/test/LoggingInterceptorTest.kt
@@ -83,6 +83,7 @@ class LoggingInterceptorTest {
       Post http://0.0.0.0/
       X-APOLLO-OPERATION-ID: 7e7c85cbf5ef3af5641552c55965608a4e5d7243f3116a486d21c3a958d34235
       X-APOLLO-OPERATION-NAME: HeroName
+      accept: multipart/mixed; deferspec=20220822, application/json
       [end of headers]
 
       HTTP: 200
@@ -103,6 +104,7 @@ class LoggingInterceptorTest {
       Post http://0.0.0.0/
       X-APOLLO-OPERATION-ID: 7e7c85cbf5ef3af5641552c55965608a4e5d7243f3116a486d21c3a958d34235
       X-APOLLO-OPERATION-NAME: HeroName
+      accept: multipart/mixed; deferspec=20220822, application/json
       [end of headers]
       {"operationName":"HeroName","variables":{},"query":"query HeroName { hero { name } }"}
 
diff --git a/tests/kotlin-js-store-1.7/yarn.lock b/tests/kotlin-js-store-1.7/yarn.lock
index 0385ad5239..dc980300d0 100644
--- a/tests/kotlin-js-store-1.7/yarn.lock
+++ b/tests/kotlin-js-store-1.7/yarn.lock
@@ -411,10 +411,10 @@ google-protobuf@3.12.2:
   resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.12.2.tgz#50ce9f9b6281235724eb243d6a83e969a2176e53"
   integrity sha512-4CZhpuRr1d6HjlyrxoXoocoGFnRYgKULgMtikMddA9ztRyYR59Aondv2FioyxWVamRo0rF2XpYawkTCBEQOSkA==
 
-graphql-helix@1.12.0:
-  version "1.12.0"
-  resolved "https://registry.yarnpkg.com/graphql-helix/-/graphql-helix-1.12.0.tgz#8a81e7c84489a0c6da968afdb54f9a979512baf9"
-  integrity sha512-wTu1m/ZFBCgzLPCg/dHO4cNy9JR5Sq/3RqDVblqrU3b/Yem7EXZtQMzG045tHqkCdbgcgQl+kIkXDur1yLfdtw==
+graphql-helix@1.13.0:
+  version "1.13.0"
+  resolved "https://registry.yarnpkg.com/graphql-helix/-/graphql-helix-1.13.0.tgz#e64dad5ef5f622ef38c97fa033f56f3d953c0104"
+  integrity sha512-cqDKMoRywKjnL0ZWCTB0GOiBgsH6d3nU4JGDF6RuzAyd35tmalzKpSxkx3NNp4H5RvnKWnrukWzR51wUq277ng==
 
 graphql-ws@5.5.0:
   version "5.5.0"