Migrating from Apollo Server 4
While Apollo Server 4 came with numerous breaking changes, the Apollo Server team is pleased to say that Apollo Server 5 has almost none!
Apollo Server 5 is a small upgrade focused largely on adjusting which versions of Node.js and Express are supported. This page tells you what to do to migrate your server from Apollo Server 4 to Apollo Server 5.
Most users will only have to:
Confirm that you are running a non-EOL version of Node.js
Maybe do a backwards-compatible upgrade of GraphQL.js
If using Express, adjust how you import
expressMiddleware
If using an HTTP proxy to make HTTP requests, adjust how you configure it
If you are still on Apollo Server v3, the migrating from Apollo Server 3 guide shows you how to migrate directly from v3 to v5.
We recommend that all users of previous versions of Apollo Server upgrade to Apollo Server 5 as soon as possible. Apollo Server 4 is deprecated, with end-of-life on January 26, 2026. Apollo Server 3 has been end-of-life since October 22, 2024. Apollo Server 2 has been end-of-life since October 22, 2023.
Require Node.js v20
Apollo Server 5 supports Node.js v20.0.0 and later. (Apollo Server 4 supports Node.js v14.16.0 and later.) This includes all non-EOL major versions at the time of release.
If you're using Node.js v14, v16, or v18, upgrade your runtime before upgrading to Apollo Server 5 to at least v20; we recommend upgrading all the way to the latest version.
If your server requires you to use an HTTP proxy to make external connections, we strongly recommend running Node.js v24 or newer, which has built-in support for communicating through HTTP proxies.
If you can't upgrade to a non-EOL version of Node.js, you can continue to use Apollo Server 4.
Require GraphQL.js v16.11.0
Apollo Server 5 supports GraphQL.js v16.11.0 and later, as a peer dependency. (Apollo Server 4 supports GraphQL.js v16.6.0 and later.)
Before upgrading to Apollo Server 5, make sure the version of graphql
in your server is at least v16.11.0. There are no backward-incompatible changes between v16.6.0 and v16.11.0 (but there are several nice improvements, including a fix to a serious bug that can crash your Node server.)
Separate package for the Express integration
Apollo Server defines a generic API for integrating with web frameworks via separately-distributed integration packages.
Apollo Server 4 includes a built-in integration with version 4 of the Express web framework directly inside the @apollo/server
package: the expressMiddleware
function exported from @apollo/server/express4
.
In Apollo Server 5, integrating with Express works the same way as integrating with any other web framework: you need to install a separate integration package. Apollo maintains an integration with Express v4 (@as-integrations/express4
), as well as an integration with Express v5 (@as-integrations/express5
). These separate integrations also work with Apollo Server 4, so you may already be using them.
This Apollo Server 4 code:
1import { expressMiddleware } from '@apollo/server/express4';
looks like this in Apollo Server 5:
1import { expressMiddleware } from '@as-integrations/express4';
You must first run npm install @as-integrations/express4
.
You can make this change while you're still running Apollo Server 4 before upgrading to Apollo Server 5, or you can make it when you upgrade.
(You may then wish to upgrade Express to v5. If you do, use @as-integrations/express5
instead; it has the same API as @as-integrations/express4
.)
Plugins use built-in Node.js fetch to make HTTP requests
Certain features require Apollo Server to make outgoing requests to Apollo GraphOS or another server in your infrastructure. Specifically, the Usage Reporting and Schema Reporting plugins make requests to Apollo GraphOS, and the Subscription Callback plugin makes requests to your GraphOS Router.
In Apollo Server 4, these plugins use the node-fetch
npm package by default.
In Apollo Server 5, these plugins use the Node.js built-in fetch
implementation by default. (Despite the similar names, these are completely different implementations.)
These implementations both make essentially the same HTTP requests, so this behavior change is largely invisible. However, the two libraries implement HTTP proxy support in different ways. If you had followed our directions to configure your server to use your HTTP proxy using the global-agent
npm package, you will need to update your server's configuration.
Note you can override how the plugins make requests by passing a
fetcher
option to theApolloServerPluginUsageReporting
,ApolloServerPluginSchemaReporting
, andApolloServerPluginSubscriptionCallback
functions, though only the usage reporting and schema reporting functions can be configured in Apollo Server 4. The only change in Apollo Server 5 is which fetcher is used by the default, so if you explicitly specify afetcher
to a reporting plugin, nothing will change in Apollo Server 5.
This is simplest if you are running Node.js v24 or newer, where the built-in fetch
implementation has support for environment-variable-based proxy configuration.
Specifically, if you have this code in Apollo Server 4:
1import { bootstrap } from 'global-agent';
2bootstrap();
and have set environment variables such as GLOBAL_AGENT_HTTP_PROXY
and GLOBAL_AGENT_NO_PROXY
, then:
Remove the
bootstrap
import and call.Remove
global-agent
from your project (egnpm uninstall global-agent
).Check what version of Node.js you are running:
If you are running Node.js v24 or later, set the
NODE_USE_ENV_PROXY
environment variable to 1.If you are running Node.js v20 or v22, follow our instructions to set the Undici global dispatcher to the
EnvHttpProxyAgent
.
If you were previously setting the
GLOBAL_AGENT_HTTP_PROXY
environment variable, set theHTTP_PROXY
environment variable to the same value instead.If you were previously setting the
GLOBAL_AGENT_HTTPS_PROXY
environment variable, set theHTTPS_PROXY
environment variable to the same value instead.If you were previously setting the
GLOBAL_AGENT_NO_PROXY
environment variable, set theNO_PROXY
environment variable to the same value instead.
Alternatively, you can continue to use node-fetch
with Apollo Server 5. To do this, run npm install node-fetch@2
, and pass it as the fetcher
option to the plugins that you use:
1import nodeFetchFetcher from 'node-fetch';
2import { ApolloServer } from '@apollo/server';
3import { ApolloServerPluginUsageReporting } from '@apollo/server/plugin/usageReporting';
4import { ApolloServerPluginSchemaReporting } from '@apollo/server/plugin/schemaReporting';
5
6const server = new ApolloServer({
7 typeDefs,
8 resolvers,
9 plugins: [
10 ApolloServerPluginUsageReporting({
11 fetcher: nodeFetchFetcher,
12 // ... other options
13 }),
14 ApolloServerPluginSchemaReporting({
15 fetcher: nodeFetchFetcher,
16 // ... other options
17 }),
18 ],
19});
With this approach, the existing global-agent
proxy configuration will continue to work. (v2 is the version of node-fetch
used by Apollo Server 4.)
Note: if you have enabled usage reporting by setting
APOLLO_KEY
andAPOLLO_GRAPH_REF
without any other configuration, you may not have a call toApolloServerPluginUsageReporting
in yourplugins
array; you can add a call that just includesfetcher
. Similarly, if you setAPOLLO_SCHEMA_REPORTING
and don't explicitly callApolloServerPluginSchemaReporting
, you can add a call toApolloServerPluginSchemaReporting
that just includesfetcher
.
Better default HTTP status for variable coercion errors
Apollo Server 3 responds to requests with variable coercion errors (eg, if a number is passed in the variables
map for a variable declared in the operation as a String
) with a 400 status code, indicating a client error.
Apollo Server 4 mistakenly responds to these requests with a 200 status code (success) by default. This was an unintended regression. Starting with Apollo Server v4.6.0, users can pass status400ForVariableCoercionErrors: true
to restore the intended behavior where variable coercion errors are treated as client errors, and we recommended this value in the documentation. However, for backwards compatibility, Apollo Server 4 still defaulted to responding with a 200 status code to these requests.
Apollo Server 5 restores the intended behavior: status400ForVariableCoercionErrors
now defaults to true.
If you have built clients or monitoring that depend on the accidental default behavior here, you can explicitly pass status400ForVariableCoercionErrors: false
to the ApolloServer
constructor to continue to respond to variable coercion errors with status 200.
We intend to remove this option in future major versions of Apollo Server. If your use case requires the ability to set status400ForVariableCoercionErrors: false
, please open an issue to let us know about it.
Standalone server does not use Express
In Apollo Server 4, the simple minimally-configurable server created with startStandaloneServer
is implemented using the Express web framework and Apollo Server's built-in expressMiddleware
; Express is itself built on top of Node's built-in HTTP server.
In Apollo Server 5, the startStandaloneServer
is built directly on top of Node's built-in HTTP server without using Express.
While the TypeScript types in Apollo Server 4 were intended to only allow you to treat the server like an http.Server
and not like an Express server, users of startStandaloneServer
could have used type-unsafe operations to interact directly with Express-specific features. Additionally, Express does support some extra HTTP-level functionality; for example, by default it sets an x-powered-by: Express
response header and a dynamic etag
response header based on the hash of the response body.
If you rely on the fact that the startStandaloneServer
is powered by Express in Apollo Server 4, you should swap to expressMiddleware
to explicitly depend on Express. You can do this before you upgrade from Apollo Server 4 to Apollo Server 5.
Alpha support for incremental delivery
Apollo Server 4 supports the incremental delivery directives @defer
and @stream
. Enabling these directives requires using v17 of GraphQL.js, which was not yet officially released at the time of AS v4.0.0. The support in Apollo Server 4 was designed specifically around the pre-release v17.0.0-alpha.2
of GraphQL.js, and requires clients to send an accept: multipart/mixed; deferSpec=20220824
header.
At the time of release of Apollo Server v5.0.0, GraphQL.js v17 is still not officially released. Newer alpha releases of GraphQL.js v17 produce a slightly different format of response.
Because GraphQL.js v17's behavior is still in flux, Apollo Server 5 does not yet support the newer incremental delivery format.
Just like in Apollo Server 4, Apollo Server 5 does not support incremental delivery when used with GraphQL.js v16, and does support incremental delivery when used with GraphQL.js v17.0.0-alpha.2
and clients set accept: multipart/mixed; deferSpec=20220824
.
The only difference in Apollo Server 5 is that Apollo Server now explicitly checks to see if its version of GraphQL.js is 17.0.0-alpha.2
, and only enables it if the version matches exactly. If you are using a newer alpha (or an official v17 release if that has happened by the time you read this), Apollo Server 5 will not support incremental delivery.
We hope to support the newer incremental delivery format in a future version of Apollo Server when GraphQL.js v17 is officially released. Note that because this is an experimental feature that currently requires the use of a pre-release of a dependency, we may drop support for the current format in a minor version release of Apollo Server 5 (but we will at least use the accept
header to return reasonable errors to clients).
Unsafe precomputedNonce
option to landing page plugins removed
Apollo Server v4.7.3 attempted to fix a challenge with using the landing page plugins on Cloudflare Workers by adding a precomputedNonce
option to avoid using crypto functions during server startup and use a fixed value instead of a random value. We quickly learned that this approach was unsafe, as the entire purpose of a nonce is for it to only be used once. The following week, Apollo Server v4.7.4 fixed the Cloudflare Workers compatibility issue in a different way that did not require a precomputed nonce.
For backwards compatibility reasons, we did not remove the precomputedNonce
option when we released v4.7.4, though we did make it log a deprecation warning.
In Apollo Server 5, the unsafe precomputedNonce
option to the landing page plugins does not exist. We do not expect that many users use this option whose non-deprecated lifetime was 8 days. If you do pass this option to a landing page plugin, you should be able to just delete it.
TypeScript build target changes
Apollo Server 4 is compiled by the TypeScript compiler targeting the ES2020 standard. Apollo Server 5 is compiled targeting the ES2023 standard. This is not expected to cause any issues, because Node.js v20 supports ES2023.
Integration test suite support library TypeScript build target change
The @apollo/server-integration-testsuite
used by integration library authors to test their integration no longer uses lib: ["dom"]
to tell TypeScript to assume DOM-related symbols are in the global namespace. If your integration library's test suite relied on this behavior, you may need to add lib: ["dom"]
to the compilerOptions
section of your test suite's tsconfig.json
. This should not affect normal use of Apollo Server, just testing for integration library authors.