Preparing for Production
Shipping GraphQL Yoga to production requires you to make some decisions about how you want to deploy your API and how you want to protect it. If you need to serve a lot of traffic, you might also need to consider caching.
Security
GraphQL by design offers you a full query language engine for fetching data from your API. This means that you can write queries that are very complex and can be very expensive to execute. This could be abused by malicious users to perform various attacks on your API.
Depending on the purpose and use-case of the GraphQL API you can take different approaches to protect your API.
Private API
If your API is private and you are the only consumer of the API, you can use persisted operations to ensure that only the operations you use are allowed to be executed.
Persisted Operations is a technique in which you extract the GraphQL operations from the client during the deployment, assign them a hash and then also store the hash and the associated operation directly on the GraphQL server or an external store from which the GraphQL server reads the operations.
When a client sends a request to the server, it will send the hash of the operation it wants to execute. The server will then look up the operation associated with the hash and execute it. With this constraint only the operations you have persisted can be executed.
Follow the Persisted Operations guide to learn how to use this technique.
Public API
When building a public API, you can’t use persisted operations as you don’t know which operations your clients will send. Instead you must use more complex techniques to protect your API.
Our recommendation is to use the GraphQL Armor library to protect your API. For Yoga we recommend to use the following plugins.
You can read more about these plugins in the GraphQL Armor documentation.
Depending on the type/complexity of GraphQL operations that are executed you might need to adjust the configuration of the plugins. Please refer to the GraphQL Armor documentation for more information.
import { createYoga } from 'graphql-yoga'
import { costLimitPlugin } from '@escape.tech/graphql-armor-cost-limit'
import { maxAliasesPlugin } from '@escape.tech/graphql-armor-max-aliases'
import { maxDepthPlugin } from '@escape.tech/graphql-armor-max-depth'
import { maxDirectivesPlugin } from '@escape.tech/graphql-armor-max-directives'
import { maxTokensPlugin } from '@escape.tech/graphql-armor-max-tokens'
export const yoga = createYoga({
plugins: [
costLimitPlugin(),
maxTokensPlugin(),
maxDepthPlugin(),
maxDirectivesPlugin(),
maxAliasesPlugin()
]
})
Caching
GraphQL Yoga by default has a built-in cache for parsing and validating GraphQL operations that are executed. However, sometimes you might want to instead also cache the results of the GraphQL operations.
This is especially useful if you have a lot of traffic and you want to reduce the load on your underlying services and/or databases. Our recommended way of caching is to use the Yoga Response Cache Plugin.
Error Reporting
In order to get notified when your GraphQL API is throwing errors, you can use an external service such as Sentry for making sure these errors don’t go unnoticed. The Sentry plugin for Yoga (Envelop), helps you getting started quickly.
Performance
Node.js comes with a built-in HTTP server implementation in node:http
module. But you can use a
faster alternative which is µWebSockets.js to
node:http
module. Even if it sounds like a WebSockets-only library, it can be used as a HTTP
server as well.
See benchmarks See how to integrate with uWebSockets.js
But keep on mind, you won’t be able to use node:http
specific libraries on top of µWebSockets.js.
For example, you won’t be able to use express
or koa
on top of µWebSockets.js.