Skip to content

Dataloader & N+1

Quail enables GraphQL::Dataloader on your schema automatically via SchemaBuilder.install_defaults. This means batched, lazy-loaded resolution is available out of the box — you don’t need to add use GraphQL::Dataloader yourself.

When graphql-ruby resolves nested associations (e.g., a list of subscriptions each loading their associated user and profile), the dataloader batches those loads into fewer queries instead of issuing one query per record. This prevents the classic N+1 problem that plagues deeply nested GraphQL queries.

For custom queries that return relations with known association depth, use ActiveRecord’s includes to preload associations in a single pass:

class MySubscribers < Quail::Query
type :subscription, connection: true, null: false
def resolve
Subscription.where(user: context[:current_user])
.includes(subscriber: { profile: { avatar_attachment: :blob } })
.order(created_at: :desc)
end
end

The includes call tells ActiveRecord to batch-load the subscriber, profile, and Active Storage avatar_attachment associations upfront. Combined with the dataloader, this keeps query count constant regardless of page size.

  • Use includes in custom Quail::Query resolvers when you know which associations the client will request. This is the most effective way to prevent N+1s in practice.
  • For auto-generated resource queries, the dataloader handles batching at the GraphQL resolver level — no extra configuration needed.
  • If you override SchemaBuilder.install_defaults or set your own dataloader_class, the automatic setup is skipped and you’re responsible for configuring the dataloader yourself.