GraphQL Yoga v2 documentation (superseded by v5): Migrating from Yoga v1 to Yoga v2. Learn how to migrate your Yoga v1 server to Yoga v2.
Installation
You can start by installing @graphql-yoga/node package.
npm i @graphql-yoga/node
yarn add @graphql-yoga/node
pnpm add @graphql-yoga/node
bun add @graphql-yoga/node
Server Setup
Yoga v1 no longer uses a class for constructing the server, the createServer function is now used.
Also, the typeDefs and resolvers config options must now be passed to a schema property.
import { GraphQLServer } from 'graphql-yoga'import { typeDefs, resolvers } from './schema'const server = new GraphQLServer({ typeDefs, resolvers })server.start()
import { createServer } from '@graphql-yoga/node'import { typeDefs, resolvers } from './schema'const server = createServer({ schema: { typeDefs, resolvers },})server.start()
Load Type Definitions from a File
In Yoga v1 it was possible to provide a file path for the typeDefs.
import * as path from 'node:path'import { GraphQLServer } from 'graphql-yoga'import { resolvers } from './schema'const server = new GraphQLServer({ typeDefs: path.join(__dirname, 'type-definitions.graphql'), resolvers})server.start()
In Yoga v2 you now need to use the fs module for Node.js.
import * as fs from 'node:fs'import * as path from 'node:path'import { createServer } from '@graphql-yoga/node'import { resolvers } from './schema'const server = createServer({ schema: { typeDefs: fs.readFileSync(path.join(__dirname, 'type-definitions.graphql'), 'utf8'), resolvers }})server.start()
In Yoga v1 you could pass a legacy graphql-tools directiveResolver implementation to the constructor.
import { GraphQLServer } from 'graphql-yoga'import { resolvers } from './schema'import { uppercaseDirectiveResolverImplementation } from './uppercase-directive-resolver-implementation'const server = new GraphQLServer({ typeDefs: /* GraphQL */ ` type Query { hi: String } `, directiveResolvers: uppercaseDirectiveResolverImplementation})server.start()
Before deciding upon using schema directives, you should consider whether your custom directive
could be instead implemented via a field argument (abstraction).
In Yoga v2 you have to leverage the mapSchema API from graphql-tools.
In GraphQL Yoga v2 you can use the context property in the same way as GraphQL Yoga v1. The value
returned from the context factory will be merged with the initial context.
The request property within the initial context is now a
Fetch API Request. It can be used for
accessing all the HTTP request parameters, such as headers or
the method (POST, GET).
import { GraphQLServer } from 'graphql-yoga'import { typeDefs, resolvers } from './schema'import { db } from './db'const server = new GraphQLServer({ typeDefs, resolvers, context(initialContext) { const authHeader =initialContext.request.headers['authorization'] ?? null return { ...initialContext, db, authHeader }} })server.start()
import { createServer } from '@graphql-yoga/node'import { typeDefs, resolvers } from './schema'import { db } from './db'const server = new GraphQLServer({ schema: { typeDefs, resolvers }, context(initialContext) { const authHeader = initialContext.request.headers.get('authorization') ?? null return { db, authHeader } }})server.start()
Middlewares
GraphQL Yoga v1 included graphql-middleware for
wrapping resolver functions with common logic. GraphQL Yoga v2 no longer includes
graphql-middleware by default as using it can result in bad performance as it wraps all field
resolvers within the schema.
If you cannot migrate your graphql-middleware code to something like graphql-tools’
mapSchema,
we recommend using the
@envelop/graphql-middleware plugin.
npm i @envelop/graphql-middleware
yarn add @envelop/graphql-middleware
pnpm add @envelop/graphql-middleware
bun add @envelop/graphql-middleware
import { GraphQLServer } from 'graphql-yoga'import { typeDefs, resolvers } from './schema'// Middleware - Permissionsconst code = 'supersecret'async function isLoggedIn(resolve, parent, args, ctx, info) { // Include your agent code asAuthorization: <token> header. const permit = ctx.request.get('Authorization') === codeif (!permit) { throw new Error(`Not authorised!`) }return resolve() }const permissions = { Query: { secured: isLoggedIn }, Me: isLoggedIn }const server = new GraphQLServer({ typeDefs, resolvers, middleware: [permissions] })server.start()
import { createServer } from '@graphql-yoga/node'import { useGraphQLMiddleware } from '@envelop/graphql-middleware'import { typeDefs, resolvers } from './schema'// Middleware - Permissionsconst code = 'supersecret'async function isLoggedIn(resolve, parent, args, ctx, info) { // Include your agent code as Authorization: <token> header. const permit = ctx.request.get('Authorization') === code if (!permit) { throw new Error(`Not authorised!`) } return resolve()}const permissions = { Query: { secured: isLoggedIn, }, Me: isLoggedIn}const server = createServer({ schema: { typeDefs, resolvers }, plugins: [useGraphQLMiddleware([permissions])]})server.start()
Replacing GraphQL Shield
If you are using graphql-shield you might want to have a look and see whether the following
plugins might replace it:
@envelop/generic-auth: authentication and simple
(directive-based) authorization on field level
GraphQL AuthZ: a modern and flexible GraphQL
authorization layer
Subscriptions
GraphQL Yoga v1 uses the old and deprecated
subscriptions-transport-ws
protocol. GraphQL Yoga v2 comes with built-in subscription support over
SSE (Server Sent Events). One benefit of this is
that you no longer need an additional library on your frontend as the SSE protocol is just simple
HTTP.
Because of the protocol change, you must migrate your GraphQL clients that execute GraphQL
subscription operations to use the new protocol. Please use the code snippets for your GraphQL
client as listed on the
handle subscription on the client documentation.
Advantages of SSE over Websockets
Transported over simple HTTP instead of a custom protocol
Built-in support for re-connection and event-id Simpler protocol
No trouble with corporate firewalls doing packet inspection
With GraphQL Yoga v1 used the unmaintained package graphql-subscriptions for the PubSub
implementation. In GraphQL Yoga v2, a newly maintained PubSub implementation is built-in.
ts import {PubSub} from 'graphql-yoga' const pubSub = new PubSub()
ts import {createPubSub} from '@graphql-yoga/node' const pubSub = createPubSub()
Type-safe PubSub Usage
The old PubSub implementation was not type-safe. Now it is possible to define all the events and
payloads. For a full reference please check out the
Subscription PubSub documentation.
import { GraphQLServer, PubSub } from 'graphql-yoga'const pubSub = new PubSub()const server = new GraphQLServer({ context: { pubSub }, typeDefs: /_ GraphQL _/ ` type Query { \_:Boolean } type Subscription { randomNumber: Int! } type Mutation { publishRandomNumber(randomNumber: Int!): Boolean }`, resolvers: { Subscription: { randomNumber: { subscribe(_, \_2, context) { returncontext.asyncIterator('randomNumber') }, resolve: (value) => value } }, Mutation: {publishRandomNumber(_, args, context) { context.pubSub.publish('randomNumber', args.randomNumber) }} } }) server.start()
Instead of the withFilter function you can now use the more modular pipe and filter functions
exported from @graphql-yoga/node. You can learn more about filtering and mapping values in the
subscription filter and map values documentation.