📣 GraphQLConf 2025 • Sept 08-10 • Amsterdam • Early bird tickets available & sponsorship opportunities open • Learn more
2025-06-19-multioption-inputs-with-oneof

Safer Multi-option Inputs with `@oneOf`

by Benjie Gillam

We’re excited to announce OneOf Input Objects has landed in the GraphQL specification! This enhancement solves a long-standing challenge in API design: how to allow users to provide exactly one of several possible options as input, in a clean and enforceable way. This feature is a small change that packs a big return for developers building modern digital products with GraphQL.

Simplifying entrypoints

Most GraphQL queries start at a single node, and traverse the data graph from there. But often, there is more than one way of locating that node; for example you might find a user by their ID, email address, or username. Traditionally, that meant multiple root-level fields:

type Query {
  user(id: ID!): User
  userByEmail(email: String!): User
  userByUsername(username: String!): User
}

(An alternative approach was a less-than-type-safe field presenting all the options along with custom runtime validation to enforce the constraints. Either way, neither solution was ideal.)

With @oneOf, you can now consolidate those options into a single, user-friendly input which ensures users supply exactly one input field, the value of which must not be null. The result: a user-friendly schema with fewer root-level fields and without sacrificing type safety:

input UserBy @oneOf {
  id: ID
  email: String
  username: String
}
 
type Query {
  user(by: UserBy!): User
}

Input polymorphism

Of course, @oneOf’s use isn’t limited to simple scalars — it can also be used to choose between multiple complex input types, allowing for polymorphism in GraphQL inputs.

Imagine you were building a user-friendly blogging website, and each post is made up of elements — paragraphs, image galleries, block quotes, code blocks, and the like. Each of these elements come with their own set of (potentially overlapping) attributes, and you want to feed a list of them into your mutation. With @oneOf you can do so in a type safe manner:

type Mutation {
  createPost(elements: [PostElementInput]): Post
}
input PostElementInput @oneOf {
  paragraph: ParagraphInput
  blockquote: BlockQuoteInput
  gallery: GalleryInput
}
input ParagraphInput {
  text: String!
}
input BlockQuoteInput {
  text: String!
  attribution: String
  attributionUrl: String
}
input GalleryInput {
  imageUrls: [String!]!
  caption: String
  attribution: String
}

What Makes @oneOf The Right Solution?

  • Backward Compatible: Existing tools, queries and clients still work, meaning no major overhauls are required. Existing clients can even use oneOf inputs without updating; just be careful to always supply exactly one value!
  • Minimal Complexity: This feature introduces only a small change to the existing type system, but delivers very significant benefits.
  • Type-Safe Input Polymorphism: Offers a safe and scalable way to accept a variety of inputs under a single structure—something previously hard to achieve in GraphQL.
  • Now part of the GraphQL standard: Several GraphQL implementations including Ruby, Java, JavaScript and .NET already ship @oneOf as a stable feature

The Bottom Line

@oneOf allows for more expressive, capable, and less overwhelming schemas, helping technical teams to move faster with increased safety. It’s simple and easy to implement, try it today!