Some clients may send several queries to the server at once (for example, Apollo Client’s query batching). You can execute them concurrently with Schema#multiplex.

Multiplex runs have their own context, analyzers and instrumentation.

Concurrent Execution

To run queries concurrently, build an array of query options, using query: for the query string. For example:

# Prepare the context for each query:
context = {
  current_user: current_user,

# Prepare the query options:
queries = [
   query: "query Query1 { someField }",
   variables: {},
   operation_name: 'Query1',
   context: context,
   query: "query Query2 ($num: Int){ plusOne(num: $num) }",
   variables: { num: 3 },
   operation_name: 'Query2',
   context: context,

Then, pass them to Schema#multiplex:

results = MySchema.multiplex(queries)

results will contain the result for each query in queries.

Apollo Query Batching

Apollo sends the batch variables in a _json param, you also need to ensure that your schema can handle both batched and non-batched queries, below is an example of the default GraphqlController rewritten to handle Apollo batches:

def execute
  context = {}

  # Apollo sends the params in a _json variable when batching is enabled
  # see the Apollo Documentation about query batching:
  result = if params[:_json]
    queries = params[:_json].map do |param|
        query: param[:query],
        operation_name: param[:operationName],
        variables: ensure_hash(param[:variables]),
        context: context
      operation_name: params[:operationName],
      variables: ensure_hash(params[:variables]),
      context: context

  render json: result

If Apollo Client has issues recognizing the result of render json: result, replace it with render body: result.to_json, content_type: 'application/json'.

Validation and Error Handling

Each query is validated and analyzed independently. The results array may include a mix of successful results and failed results

Multiplex-Level Context

You can add values to Execution::Multiplex#context by providing a context: hash:

MySchema.multiplex(queries, context: { current_user: current_user })

This will be available to instrumentation as multiplex.context[:current_user] (see below).

Multiplex-Level Analysis

You can analyze all queries in a multiplex by adding a multiplex analyzer. For example:

class MySchema < GraphQL::Schema do
  # ...

The API is the same as query analyzers, with some considerations:

Multiplex analyzers may return AnalysisError to halt execution of the whole multiplex.

Multiplex Instrumentation

You can add hooks for each multiplex run with multiplex instrumentation.

An instrumenter must implement .before_multiplex(multiplex) and .after_multiplex(multiplex). Then, it can be mounted with instrument(:multiplex, MyMultiplexAnalyzer). See Execution::Multiplex for available methods.

For example:

# Count how many queries are in the multiplex run:
module MultiplexCounter
  def self.before_multiplex(multiplex)"Multiplex size: #{multiplex.queries.length}")

  def self.after_multiplex(multiplex)

# ...

class MySchema < GraphQL::Schema
  # ...
  instrument(:multiplex, MultiplexCounter)

Now, MultiplexCounter.before_multiplex will be called before each multiplex and .after_multiplex will run after each multiplex.