NOTE: this document is kept for historic purposes; [`@oneOf`](https://github.com/graphql/graphql-spec/pull/825) gained RFC3 status in May 2025.
At a glanceβ
- Identifier: InputUnion
- Stage: RFC0: Strawman
- Champion: -
- PR: -
- Related:
Timelineβ
- RFC document updated on 2025-06-05 by Benjie
- RFC document updated on 2023-11-28 by Benjie Gillam
- RFC document updated on 2023-11-28 by Benjie Gillam
- RFC document updated on 2021-09-03 by Lee Byron
- RFC document updated on 2021-09-02 by Ivan Goncharov
- RFC document updated on 2021-09-02 by ericvergnaud
- RFC document updated on 2021-04-05 by Lee Byron
- RFC document updated on 2020-11-18 by Evan Huus
- RFC document updated on 2020-11-04 by Benjie Gillam
- RFC document updated on 2020-09-30 by Dan Freeman
- RFC document updated on 2020-07-02 by Joel Turkel
- RFC document updated on 2020-06-25 by Valeriy Protopopov
- RFC document updated on 2020-06-12 by Benedikt Franke
- RFC document updated on 2020-06-11 by Benedikt Franke
- RFC document updated on 2020-06-11 by Benedikt Franke
- RFC document updated on 2020-05-28 by Lee Byron
- RFC document updated on 2020-05-08 by Blake Gentry
- RFC document updated on 2020-04-30 by Lee Byron
- RFC document updated on 2020-04-01 by Vince Foley
- RFC document updated on 2020-03-05 by Vince Foley
- RFC document updated on 2020-03-05 by Vince Foley
- RFC document updated on 2020-02-06 by Lee Byron
- RFC document updated on 2020-01-31 by Benjie Gillam
- RFC document updated on 2020-01-25 by Benjie Gillam
- RFC document updated on 2020-01-09 by Vince Foley
- RFC document updated on 2019-12-17 by Benjie Gillam
- RFC document updated on 2019-12-11 by Benjie Gillam
- RFC document updated on 2019-12-04 by Benjie Gillam
- RFC document updated on 2019-11-28 by Vince Foley
- RFC document updated on 2019-11-26 by Benedikt Franke
- RFC document updated on 2019-11-11 by Benjie Gillam
- RFC document updated on 2019-11-11 by Vince Foley
- RFC document updated on 2019-11-11 by Vince Foley
- RFC document updated on 2019-11-11 by Vince Foley
- RFC document updated on 2019-11-09 by Evan Huus
- RFC document updated on 2019-11-09 by Evan Huus
- RFC document updated on 2019-11-07 by Lee Byron
- RFC document updated on 2019-10-22 by Benjie Gillam
- RFC document updated on 2019-10-21 by Vince Foley
- RFC document updated on 2019-10-14 by Vince Foley
- RFC document updated on 2019-10-05 by Benjie Gillam
- RFC document updated on 2019-10-03 by Ivan Goncharov
- RFC document updated on 2019-10-03 by Vince Foley
- RFC document updated on 2019-10-01 by Vince Foley
- RFC document updated on 2019-09-19 by Vince Foley
- RFC document updated on 2019-09-15 by Vince Foley
- RFC document created on 2019-06-20 by Vince Foley
NOTE: this document is kept for historic purposes;
@oneOfgained RFC3 status in May 2025.
RFC: GraphQL Input Unionβ
The addition of an Input Union type has been discussed in the GraphQL community for many years now. The value of this feature has largely been agreed upon, but the implementation has not.
This document attempts to bring together all the various solutions and perspectives that have been discussed with the goal of reaching a shared understanding of the problem space.
From that shared understanding, the GraphQL Working Group aims to reach a consensus on how to address the proposal.
Notes from the 2020/5/28 meeting: https://gist.github.com/leebyron/f7f9d81c7ca5259357fab5d82a4c0621
Contributingβ
To help bring this idea to reality, you can contribute PRs to this RFC document.
π Problem Statement
GraphQL currently provides polymorphic types that enable schema authors to model complex Object types that have multiple shapes while remaining type-safe, but lacks an equivilant capability for Input types.
Over the years there have been numerous proposals from the community to add a polymorphic input type. Without such a type, schema authors have resorted to a handful of work-arounds to model their domains. These work-arounds have led to schemas that aren't as expressive as they could be, and schemas where mutations that ideally mirror queries are forced to be modeled differently.
π Problem Sketch
To understand the problem space a little more, we'll sketch out an example that explores a domain from the perspective of a Query and a Mutation. However, it's important to note that the problem is not limited to mutations, since
Inputtypes are used in field arguments for any GraphQL operation type.Let's imagine an animal shelter for our example. When querying for a list of the animals, it's easy to see how abstract types are useful - we can get data specific to the type of the animal easily.
{
animalShelter(location: "Portland, OR") {
animals {
__typename
name
age
... on Cat { livesLeft }
... on Dog { breed }
... on Snake { venom }
}
}
}However, when we want to submit data, we can't use an
interfaceorunion, so we must model around that.One technique commonly used to is a tagged union pattern. This essentially boils down to a "wrapper" input that isolates each type into its own field. The field name takes on the convention of representing the type.
mutation {
logAnimalDropOff(
location: "Portland, OR"
animals: [
{cat: {name: "Buster", age: 3, livesLeft: 7}}
]
)
}Unfortunately, this opens up a set of problems, since the Tagged union input type actually contains many fields, any of which could be submitted.
input AnimalDropOffInput {
cat: CatInput
dog: DogInput
snake: SnakeInput
}This allows nonsensical mutations to pass GraphQL validation, for example representing an animal that is both a
Catand aDog.mutation {
logAnimalDropOff(
location: "Portland, OR"
animals: [
{
cat: {name: "Buster", age: 3, livesLeft: 7},
dog: {name: "Ripple", age: 2, breed: WHIPPET}
}
]
)
}In addition, relying on this layer of abstraction means that this domain must be modelled differently across input & output. This can put a larger burden on the developer interacting with the schema, both in terms of lines of code and complexity.
// JSON structure returned from a query
{
"animals": [
{"__typename": "Cat", "name": "Ruby", "age": 2, "livesLeft": 9}
{"__typename": "Snake", "name": "Monty", "age": 13, "venom": "POISON"}
]
}// JSON structure submitted to a mutation
{
"animals": [
{"cat": {"name": "Ruby", "age": 2, "livesLeft": 9}},
{"snake": {"name": "Monty", "age": 13, "venom": "POISON"}}
]
}Another approach is to use an input type with a discriminator and input fields for all possible member types.
mutation {
logAnimalDropOff(
location: "Portland, OR"
animals: [
{type: CAT, name: "Buster", age: 3, livesLeft: 7},
{type: DOG, name: "Ripple", age: 2, breed: WHIPPET}
]
)
}
input AnimalDropOffInput {
type: AnimalType!
name: String!
age: Int!
breed: DogBreed # only applies when type = DOG
livesLeft: Int # only applies when type = CAT
venom: VenomType # only applies when type = SNAKE
}This results in more consistent modeling between input & output but still allows nonsensical inputs to pass GraphQL validation.
Another common approach is to provide a unique mutation for every type. A schema employing this technique might have
logCatDropOff,logDogDropOffandlogSnakeDropOffmutations. This removes the potential for modeling non-sensical situations, but it explodes the number of mutations in a schema, making the schema less accessible. If the type is nested inside other inputs, this approach simply isn't feasable.These workarounds only get worse at scale. Real world GraphQL schemas can have dozens if not hundreds of possible types for a single
InterfaceorUnion.The goal of the Input Union is to bring a polymorphic type to Inputs. This would enable us to model situations where an input may be of different types in a type-safe and elegant manner, like we can with outputs.
mutation {
logAnimalDropOff(
location: "Portland, OR"
# Problem: we need to determine the type of each Animal
animals: [
# This is meant to be a CatInput
{name: "Buster", age: 3, livesLeft: 7},
# This is meant to be a DogInput
{name: "Ripple", age: 2}
]
)
}In this mutation, we encounter the main challenge of the Input Union - we need to determine the correct type of the data submitted.
A wide variety of solutions have been explored by the community, and they are outlined in detail in this document under Possible Solutions.
π¨ Prior Art
Many other technologies provide polymorphic types, and have done so using a variety of techniques.
Tech Type Read Write GraphQL Union β