Table of Contents


Fields are how you can navigate through a GraphQL schema and get precisely the data you want for your front end. You will find fields in all sorts of flavors and places, and this area will guide you through the basics and intermediate of them.

Basic Concepts

field :name, :string

A field will always be composed of a name, a type, and a sequence of settings provided through named arguments.

The only thing required is the name, preferably as a symbol in snake case.

By default, the type will be :string, unless the field’s name is :id, which automatically makes it of the :id type.

field :name
# Is the same as
field :name, :string


field :id
# Is the same as
field :id, :id

It’s always recommended to provide a type, even when it is :id, :id, for clarity.

The type represents what the field will deliver when it is an output field or what it accepts when it is an input field.

Fields can also be configured using a block, but just for some options:

field(:name, :string) do
  desc 'The name of the thing'
  # ...

Additional Options

desc:/description: String = nil

Allows documenting the field. This value can be retrieved using introspection or during a to_gql output. Within the block, desc works as a syntax sugar for self.description = ''.

null: Boolean = true

Marks if the field accepts or can deliver a null value.

array: Boolean = false

Marks if the field accepts or can deliver an array of values.

As of now, fields only support one-dimensional arrays.

nullable: Boolean = true

Marks if the array may contain null values.

full: Boolean = false

A shortcut to null: false, array: true, nullable: false.

enabled: Boolean = nil

Marks if the field is available to be used.

disabled: Boolean = false

Marks if the field is unavailable to be used.

directives: Directive/[Directive] = nil

One or more directives to attach to the field. Within the block, use the use method.

Input Fields

Input fields will be present in Input-type objects. Those fields will help in the process of translating external values into Ruby values.

# app/graphql/inputs/user_input.rb
class GraphQL::UserInput < GraphQL::Input
  field :name, :string, null: false,
    desc: 'The name of the user'

Read more about inputs.

Additional Options

default: Object = nil

Sets the default value of the field. The field will use its default value if no external value is provided. Beware, the default value will also be used when the provided external value is nil.

Output Fields

Output fields will be present in several places, like Objects, Interfaces, Schemas, and Sources, to name a few.

Their purpose is to either give you a plain value (leaf) or access to types that have nested fields (branch).

# app/graphql/objects/user.rb
class GraphQL::User < GraphQL::Object
  # Leaf field
  field :name, :string, null: false,
    desc: 'The name of the user'

# app/graphql/app_schema.rb
query_fields do
  # Branch field
  field :me, 'User', null: false,
    desc: 'Get information about the current user'

Additional Options

arguments: Argument/[Argument] = nil

One or more arguments to be added to the field. Within the block, use the argument method.

method_name: Symbol = nil

The name of the method used to fetch the field’s data when resolving the field.

deprecated: Boolean/String = nil

Marks the field as deprecated when provided with a truthy value. Additionally, you can pass a String to set the reason for the deprecation.

broadcastable: Boolean = nil

Marks if the field is broadcastable or not, which is only relevant when working with broadcasting subscriptions.


All output fields accept additional arguments. This list of unique arguments allows for exchanging expected behaviors that the request has about this field. Arguments accept both leaf values or Inputs.

You have some options while adding your arguments:

# Any of these options, that produces the same result,
# are good for a short list of arguments (1 - 2)
field :name, :string,
  arguments: argument(:first, :bool) + argument(:last, :bool)
field :name, :string,
  arguments: argument(:first, :bool) & argument(:last, :bool)
field :name, :string,
  arguments: [argument(:first, :bool), argument(:last, :bool)]

# In this binding, you can also shorten the line by using `arg` instead
field :name, :string, arguments: arg(:first, :bool) + arg(:last, :bool)

# For a more extensive list of arguments,
# use the block of the definition of the field
field(:name, :string) do
  argument :first, :bool, default: true
  argument :last, :bool, default: true
  argument :mid, :bool

  # This binding does not support the `arg` alias

# You can also use a syntax sugar
field :user, 'User', arguments: id_argument
# Which is equivalent to
field :user, 'User', arguments: argument(:id, :id, null: false)
# You can customize the name of the argument and all the other options as well
id_argument(:pid, null: true, desc: 'ID')
# Which is equivalent to
argument(:pid, :id, null: true, desc: 'ID')

Read more about arguments.

Resolving Fields

Resolving fields is the process of putting the data into the response during a request. There are several ways a field can be resolved. For now, the important thing to know is the meaning of the :method_name option. It tells where the data will come from. When not defined, the request assumes it is the same as the field’s name.

Standalone-defined fields fallback to :resolve

Read more about requests.

Mutation Fields

Mutations fields are a special type of output field that only exists in schemas, in the mutation_fields list more precisely. Their purpose is to inform the request that one extra step needs to happen before the field can actually be resolved. This step, called perform, will make changes in the data under GraphQL.

# app/graphql/app_schema.rb
mutation_fields do
  field :update_user, 'User', null: false,
    desc: 'Change the information about the current user'

Read more about mutations and performing fields.

Subscription Fields

Subscription Fields are another special type of output field that only exists in, in the subscription_fields list more precisely. Their purpose is to return values and sign the request for updates that may happen with the data it first returned.

# app/graphql/app_schema.rb
subscription_fields do
  field :me, 'User',
    desc: 'Get notified whenever the current user has been updated'

Read more about subscriptions and fields subscription.

Authorized Fields

Unavailable This feature is yet to be published.

All output fields support an authorization step. This step will attempt to check if the request and its context provide enough scope to resolve the field.

Read more about authorization.


Output fields support a series of events. Those events happens during the process of a request. Special types of output fields may also have special types of events. Here is how you can listen to events:

field(:name, :string) do
  on(:prepare) { |event| puts event.inspect }

Read more about events.


All fields support directives. Directives are an advanced feature of GraphQL and this gem. Just as a reference, here is how you can add directives to fields:

field :name, :string, directives:
# It also supports concatenating with + or &. These are all equivalent
field :name, :string,
  directives: +
field :name, :string,
  directives: &
field :name, :string,
  directives: [,]

# OR the block approach
field(:name, :string) do
  # These are the same thing
  use :deprecated, reason: 'Just because'
  use GraphQL::DeprecatedDirective(reason: 'Just because')
  use 'Just because')

# Shortcut for deprecated directive
field(:name, :string, deprecated: 'Just because')

Read more about directives.

Chaining Definition

You may have noticed that in some examples, a chaining approach was used to configure a field. This is widely available for the methods you would likely call within the block.

field(:name, :string)
  .argument(:first, :bool)
  .argument(:last, :bool)
  .use(:deprecated, reason: 'Just because')
  .on(:prepare) { |event| puts event.inspect }
  .resolve { 'The name!' }

However, the recommendation is to use just in the simple situations.

Read more about recommendations.

I18n Support

If your GraphQL API is served as a public API, it may be interesting to publish the documentation in several languages. Although you can’t change the name of the fields, the description can be defined in your YAML files.

# app/graphql/app_schema.rb
query_fields do
  field :user, 'User'
# config/locales/en.yml
      user: Information about the current user
type _Query {
  # Information about the current user
  user: User!

Affects Performance This is a heavy process, so it is recommended to enable only when delivering the documentation of your API or in development mode.

This feature is coordinated by config.enable_i18n_descriptions and config.i18n_scopes.

Read more about I18n.

Changing Fields

Field definitions are not final. At any given point, you can change some of its behaviors. However, changing it anywhere will affect the GraphQL application entirely.

This is useful when controlling the enabled/disabled state of fields and proxy fields.

# app/graphql/interfaces/animal.rb
class GraphQL::Animal < GraphQL::Interface
  field :name, :string, desc: 'The name of the animal'

# app/graphql/objects/cat.rb
class GraphQL::Cat < GraphQL::Object
  # Fields are imported as proxies
  implements 'Animal'

  # Changes only the local version of the field
  change_field :name, desc: 'The name of the cat'

# app/graphql/objects/dog.rb
class GraphQL::Dog < GraphQL::Object
  # Fields are imported as proxies
  implements 'Animal'

  # A block allows changing other things
  change_field(:name, desc: 'The name of the dog') do
    argument(:nickname, :bool, null: false, default: false)

You are allowed to change the null, nullable, disabled, enabled, description, default, and method_name values, as well as increment the arguments and directives within a block.

Proxy fields is an advanced feature. Read more about proxy fields.

Additional Notes

All fields have 6 indicators of exactly what they are:

Is it associated with a leaf type?
Is it being used as an input of data?
Is it being used as an output of data?
Does it have mutation capabilities?
Does it have subscription capabilities?
Is it a proxy of another field?

This is the tree of field classes and what modules they implement.

↳ Rails::GraphQL::Field
  ↳ InputField
      + TypedField
  ↳ OutputField
      + AuthorizedField
      + ResolvedField
      + TypedField
    ↳ MutationField
    ↳ SubscriptionField

represents inheritance and + represents composition