• v3 (beta)
  • Features
  • Defer and Stream

Incremental Delivery

As our app grows, the queries get bigger and grow with GraphQL's request/response model. Usually, the server will only send the response back once all the data requested in the query is ready. However, not all requested data is of equal importance, and the client may not need all of the data at once. To remedy this, GraphQL specification working group is working on introducing new @defer and @stream directives which allows applications to request a subset of data which is critical and get the rest of the data in subsequent responses from the server. This proposal is in Stage 2, meaning GraphQL libraries can start implementing this as experimental feature to provide feedback to the working group.

GraphQL Yoga comes with a plugin to enable incremental delivery!

Installation

yarn add @graphql-yoga/plugin-defer-stream

Quick Start

server.ts
import { createYoga, createSchema } from 'graphql-yoga'
import { createServer } from 'node:http'
import { useDeferStream } from '@graphql-yoga/plugin-defer-stream'
 
const typeDefs = /* GraphQL */ `
  type Query {
    alphabet: [String!]!
    """
    A field that resolves fast.
    """
    fastField: String!
 
    """
    A field that resolves slowly.
    Maybe you want to @defer this field ;)
    """
    slowField(waitFor: Int! = 5000): String
  }
`
 
const wait = (time: number) =>
  new Promise((resolve) => setTimeout(resolve, time))
 
const resolvers = {
  Query: {
    async *alphabet() {
      for (const character of ['a', 'b', 'c', 'd', 'e', 'f', 'g']) {
        yield character
        await wait(1000)
      }
    },
    fastField: async () => {
      await wait(100)
      return 'I am speed'
    },
    slowField: async (_, { waitFor }) => {
      await wait(waitFor)
      return 'I am slow'
    }
  }
}
 
const yoga = createYoga({
  schema: createSchema({
    typeDefs,
    resolvers
  }),
  plugins: [useDeferStream()]
})
 
const server = createServer(yoga)
 
server.listen(4000, () => {
  console.info('Server is running on http://localhost:4000/graphql')
})

Start the server

Defer Example

Visit http://localhost:4000/graphql and paste the following operation into the left panel.

query SlowAndFastFieldWithDefer {
  ... on Query @defer {
    slowField
  }
  fastField
}

Then press the Play (Execute Query) button.

Alternatively, you can also send the defer operation via curl.

curl -g -X POST -H "accept:multipart/mixed" -H "content-type: application/json" -d '{"query":"query SlowAndFastFieldWithDefer { ... on Query @defer { slowField } fastField }"}' http://localhost:4000/graphql

Stream Example

Visit http://localhost:4000/graphql and paste the following operation into the left panel.

query StreamAlphabet {
  alphabet @stream
}

Then press the Play (Execute Query) button.

Alternatively, you can also send the stream operation via curl.

curl -g -X POST -H "accept:multipart/mixed" -H "content-type: application/json" -d '{"query":"query StreamAlphabet { alphabet @stream }"}' http://localhost:4000/graphql
Last updated on November 3, 2022