From 3bed514b5f336a7fa7954f57542442caa4139857 Mon Sep 17 00:00:00 2001 From: Yaacov Rydzinski Date: Tue, 2 Jun 2026 16:04:24 +0300 Subject: [PATCH] docs: update documentation for v17 release candidate --- website/pages/api-v17/execution.mdx | 10 + website/pages/api-v17/graphql.mdx | 532 ++++++++++++++++++ website/pages/api-v17/graphql/_meta.ts | 4 + website/pages/api-v17/validation.mdx | 2 +- website/pages/docs/defer-stream.mdx | 12 +- .../experimental-specification-features.mdx | 10 +- website/pages/docs/fragment-arguments.mdx | 22 +- website/pages/docs/getting-started.mdx | 10 +- website/pages/docs/going-to-production.mdx | 7 + website/pages/docs/graphql-errors.mdx | 8 +- website/pages/docs/index.mdx | 10 +- website/pages/upgrade-guides/v16-v17.mdx | 209 +++++-- 12 files changed, 775 insertions(+), 61 deletions(-) diff --git a/website/pages/api-v17/execution.mdx b/website/pages/api-v17/execution.mdx index 1edabae112..969fe5b48f 100644 --- a/website/pages/api-v17/execution.mdx +++ b/website/pages/api-v17/execution.mdx @@ -1201,6 +1201,11 @@ and the fragments defined in the query document Schema used for execution. + + document + + Parsed GraphQL document being executed. + fragmentDefinitions @@ -1231,6 +1236,11 @@ and the fragments defined in the query document Operation variable values with source metadata and coerced runtime values. + + rawVariableValues + + Raw variable values provided by the caller before coercion. + fieldResolver diff --git a/website/pages/api-v17/graphql.mdx b/website/pages/api-v17/graphql.mdx index 792467022d..6a5f5a6d27 100644 --- a/website/pages/api-v17/graphql.mdx +++ b/website/pages/api-v17/graphql.mdx @@ -22,6 +22,7 @@ metadata, that do not belong to a narrower submodule. For documentation purposes, these exports are grouped into the following categories: - [Development Mode](/api-v17/graphql#category-development-mode) +- [Diagnostics](/api-v17/graphql#category-diagnostics) - [Request Pipeline](/api-v17/graphql#category-request-pipeline) - [Harness](/api-v17/graphql#category-harness) - [Version](/api-v17/graphql#category-version) @@ -105,6 +106,537 @@ enableDevMode(); isDevModeEnabled(); // => true ``` +## Category: Diagnostics + + + +### Types + +#### GraphQLParseContext + +**Interface.** * Context published on `graphql:parse`. + +
+ +
Members
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
sourceSource text or source object passed to the parser.
error?Error thrown while parsing, when parsing fails.
result?Parsed document, when parsing succeeds.
+ +
+ +#### GraphQLValidateContext + +**Interface.** * Context published on `graphql:validate`. + +
+ +
Members
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
schemaSchema used for validation.
documentParsed document being validated.
error?Error thrown while validating, when validation fails abruptly.
result?Validation errors returned by validation.
+ +
+ +#### GraphQLExecuteContext + +**Interface.** * Context published on `graphql:execute`. + +
+ +
Members
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
schemaSchema used for execution.
documentParsed document being executed.
rawVariableValuesRaw variable values provided by the caller before coercion.
operationNameSelected operation name, if one is available.
operationTypeSelected operation type, if one is available.
error?Error thrown while executing, when execution fails abruptly.
result?Execution result returned by execution.
+ +
+ +#### GraphQLExecuteRootSelectionSetContext + +**Interface.** * Context published on `graphql:execute:rootSelectionSet`. + +
+ +
Members
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
schemaSchema used for execution.
documentParsed document being executed.
operationOperation definition selected for execution.
rawVariableValuesRaw variable values provided by the caller before coercion.
operationNameSelected operation name, if one is available.
operationTypeSelected operation type.
error?Error thrown while executing the root selection set.
result?Execution result returned from the root selection set.
+ +
+ +#### GraphQLExecuteVariableCoercionContext + +**Interface.** Context published on `graphql:execute:variableCoercion`. + +Coercion runs synchronously inside argument validation, so only the +`start`/`end` (and, on a thrown error, [`error`](/api-v17/error)) lifecycle fires. When +coercion produces variable errors it does not throw; instead `result` +carries the `errors` array, mirroring `graphql:validate`. + +
+ +
Members
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
schemaSchema used for variable coercion.
documentParsed document being executed.
operationOperation definition whose variables are being coerced.
rawVariableValuesRaw variable values provided by the caller before coercion.
operationNameSelected operation name, if one is available.
operationTypeSelected operation type.
error?Error thrown while coercing variables, when coercion fails abruptly.
result?Coerced variable values or coercion errors returned by coercion.
+ +
+ +#### GraphQLSubscribeContext + +**Interface.** * Context published on `graphql:subscribe`. + +
+ +
Members
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
schemaSchema used for subscription execution.
documentParsed subscription document.
rawVariableValuesRaw variable values provided by the caller before coercion.
operationNameSelected operation name, if one is available.
operationTypeSelected operation type, if one is available.
error?Error thrown while subscribing, when subscription setup fails abruptly.
result?Subscription response stream or execution result returned by subscribe.
+ +
+ +#### GraphQLResolveContext + +**Interface.** * Context published on `graphql:resolve`. + +
+ +
Members
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
fieldNameField name being resolved.
aliasResponse alias for the field being resolved.
parentTypeParent type name for the field being resolved.
fieldTypeReturn type string for the field being resolved.
argsArgument values passed to the resolver.
isDefaultResolverWhether the field is using the default resolver.
fieldPathResponse path for the field being resolved.
error?Error thrown by the resolver, when resolution fails.
result?Value returned by the resolver.
+ +
+ +#### GraphQLChannelContextByName + +**Interface.** * Mapping from tracing channel name to the context type published on it. + +
+ +
Members
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
graphql:parseContext published on {"graphql:parse"}.
graphql:validateContext published on {"graphql:validate"}.
graphql:executeContext published on {"graphql:execute"}.
graphql:execute:variableCoercionContext published on {"graphql:execute:variableCoercion"}.
graphql:execute:rootSelectionSetContext published on {"graphql:execute:rootSelectionSet"}.
graphql:subscribeContext published on {"graphql:subscribe"}.
graphql:resolveContext published on {"graphql:resolve"}.
+ +
+ +#### GraphQLChannels + +**Interface.** The collection of tracing channels graphql-js emits on. Application +performance monitoring (APM) tools subscribe to these by name on their own +`node:diagnostics_channel` import; both paths land on the same channel +instance because `tracingChannel(name)` is cached by name. + +
+ +
Members
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
executeTracing channel for {"graphql:execute"}.
executeVariableCoercionTracing channel for {"graphql:execute:variableCoercion"}.
executeRootSelectionSetTracing channel for {"graphql:execute:rootSelectionSet"}.
parseTracing channel for {"graphql:parse"}.
validateTracing channel for {"graphql:validate"}.
resolveTracing channel for {"graphql:resolve"}.
subscribeTracing channel for {"graphql:subscribe"}.
+ ## Category: Request Pipeline
diff --git a/website/pages/api-v17/graphql/_meta.ts b/website/pages/api-v17/graphql/_meta.ts index 01bfd14665..625de06299 100644 --- a/website/pages/api-v17/graphql/_meta.ts +++ b/website/pages/api-v17/graphql/_meta.ts @@ -3,6 +3,10 @@ const meta = { title: 'Category: Development Mode', href: '/api-v17/graphql#category-development-mode', }, + diagnostics: { + title: 'Category: Diagnostics', + href: '/api-v17/graphql#category-diagnostics', + }, 'request-pipeline': { title: 'Category: Request Pipeline', href: '/api-v17/graphql#category-request-pipeline', diff --git a/website/pages/api-v17/validation.mdx b/website/pages/api-v17/validation.mdx index 1055533069..c6e926e3fb 100644 --- a/website/pages/api-v17/validation.mdx +++ b/website/pages/api-v17/validation.mdx @@ -1207,7 +1207,7 @@ validate(schema, validDocument, [DeferStreamDirectiveOnRootFieldRule]); // => [] Defer And Stream Directives Are Used On Valid Operations -A GraphQL document is only valid if defer directives are not used on root mutation or subscription types. +A GraphQL document is only valid if defer and stream directives are not used on root mutation or subscription types. **Signature:** diff --git a/website/pages/docs/defer-stream.mdx b/website/pages/docs/defer-stream.mdx index 5252fa26a5..5b5cf85048 100644 --- a/website/pages/docs/defer-stream.mdx +++ b/website/pages/docs/defer-stream.mdx @@ -165,11 +165,14 @@ increase concurrent work. Measure before enabling it broadly. GraphQL.js validates the current incremental delivery rules: -- `@defer` and `@stream` are not supported on subscription operations. +- Active `@defer` and `@stream` are not supported on subscription operations, + including through named fragments. - `@stream` must be used on list fields. - `@stream(initialCount:)` must be non-null. - Active `@defer` and `@stream` labels must be unique. -- Root field usage must follow the current proposal rules. +- Root-field restrictions apply only to mutation and subscription root + selections, including through fragments whose type condition matches the root + type through an interface. Query root selections may use incremental delivery. - Multiple active `@stream` instances cannot target the same field instance. Those checks are exposed through the validation rules @@ -177,8 +180,9 @@ Those checks are exposed through the validation rules `DeferStreamDirectiveOnValidOperationsRule`, and `StreamDirectiveOnListFieldRule`. -If a fragment is shared between query and subscription operations, use the -directive `if` argument to disable incremental behavior in the subscription. +If a fragment is shared between query and subscription operations, use a +variable-backed `if` argument on `@defer` or `@stream`, or applicable `@skip` +and `@include` directives, to disable incremental behavior in the subscription. ```graphql subscription Events($incremental: Boolean! = false) { diff --git a/website/pages/docs/experimental-specification-features.mdx b/website/pages/docs/experimental-specification-features.mdx index 165f551aa2..0da607e2e4 100644 --- a/website/pages/docs/experimental-specification-features.mdx +++ b/website/pages/docs/experimental-specification-features.mdx @@ -5,11 +5,11 @@ sidebarTitle: Experimental Specification Features # Experimental Specification Features -GraphQL.js v17 beta supports several GraphQL specification proposals. This page -lists experimental features available in the v17 beta line; not every feature -listed here is new to v17. These features are intentionally explicit: syntax -usually requires a parser option or schema directive, and execution behavior -usually requires a specific executor. +GraphQL.js v17 release candidate supports several GraphQL specification +proposals. This page lists experimental features available in the v17 +release-candidate line; not every feature listed here is new to v17. These +features are intentionally explicit: syntax usually requires a parser option or +schema directive, and execution behavior usually requires a specific executor. GraphQL.js-specific runtime APIs, such as abort signals, execution hooks, and the harness API, are documented separately because they are not GraphQL language diff --git a/website/pages/docs/fragment-arguments.mdx b/website/pages/docs/fragment-arguments.mdx index 2d4c1205ec..a39854dafd 100644 --- a/website/pages/docs/fragment-arguments.mdx +++ b/website/pages/docs/fragment-arguments.mdx @@ -14,12 +14,19 @@ import { Callout } from 'nextra/components'; GraphQL operation variables are defined at the operation level. That works for many documents, but reusable fragments sometimes need local parameters. Fragment -arguments let a fragment define its own variables and let each fragment spread -provide values for those variables. +arguments let a named fragment define its own variables and let each named +fragment spread provide values for those variables. -The feature is also called fragment variables because the fragment-level -parameters are conceptually "variables" scoped to that fragment. They are passed -as arguments on the fragment spread, using syntax similar to field arguments. +Earlier GraphQL.js versions used the name "fragment variables" for experimental +syntax that allowed fragment definitions to declare local variables. That syntax +could be parsed, printed, and traversed by GraphQL.js consumers, but GraphQL.js +did not provide the runtime machinery to execute operations with values for +those variables. + +GraphQL.js v17 uses the name "fragment arguments" for the end-to-end feature: +named fragments can define local variables, named fragment spreads can pass +values for those variables, and execution applies those values with coercion and +default handling. ## Changed from legacy fragment variables @@ -113,7 +120,8 @@ distinct names are easier for humans and tools to follow. Resolvers do not need a separate API for fragment arguments. By the time a field resolver runs, GraphQL.js has applied the fragment argument values to the -field arguments, directives, and nested fragment spreads that reference them. +field arguments, directives, and nested named fragment spreads that reference +them. ## AST and tooling changes @@ -127,7 +135,7 @@ When enabled, GraphQL.js adds: The printer and visitor understand these nodes in v17. Tooling that uses custom visitors should include the new node kind when it needs to inspect or transform -fragment spread arguments. +arguments on named fragment spreads. ```js import { Kind, visit } from 'graphql'; diff --git a/website/pages/docs/getting-started.mdx b/website/pages/docs/getting-started.mdx index 6f7b089836..f5de66e289 100644 --- a/website/pages/docs/getting-started.mdx +++ b/website/pages/docs/getting-started.mdx @@ -20,9 +20,8 @@ and arrow functions, so if you aren't familiar with them you might want to read > Alternatively you can start from [this StackBlitz](https://stackblitz.com/edit/stackblitz-starters-znvgwr) - if you choose > this route you can skip to [Basic Types](./basic-types.mdx). -GraphQL.js v16 is the current stable release. v17 is available as an alpha for -early testing and feedback. The alpha may change and should not be used in -production. +GraphQL.js v16 is the current stable release. v17 is available as a release +candidate for final testing and feedback before the stable v17 release. ## Setting Up Your Project @@ -50,10 +49,11 @@ Update your `package.json` to include `"type": "module"`: } ``` -To try the v17 alpha instead: +To try the v17 release candidate instead, use Node.js 22 or newer and install +the `rc` package tag: ```sh npm2yarn -npm install graphql@alpha --save +npm install graphql@rc --save ``` ## Writing Code diff --git a/website/pages/docs/going-to-production.mdx b/website/pages/docs/going-to-production.mdx index aa57121dc0..5dd0fc674f 100644 --- a/website/pages/docs/going-to-production.mdx +++ b/website/pages/docs/going-to-production.mdx @@ -235,6 +235,13 @@ GraphQL.js allows you to hook into the execution pipeline using: - `parse` and `validate`: Trace early steps - `formatResponse`: Attach metadata +Starting in v17, GraphQL.js also publishes lifecycle events on Node.js +`node:diagnostics_channel` tracing channels for parse, validation, execution, +subscription setup, variable coercion, root selection set execution, and field +resolution. These channels are mainly for application performance monitoring +(APM) tools and other tracing integrations, which can subscribe to the +`graphql:*` channels without changing application request code. + Tracing tools that work with GraphQL include: - [Apollo Studio](https://www.apollographql.com/docs/studio/) diff --git a/website/pages/docs/graphql-errors.mdx b/website/pages/docs/graphql-errors.mdx index 13e286f025..6c0b4d263d 100644 --- a/website/pages/docs/graphql-errors.mdx +++ b/website/pages/docs/graphql-errors.mdx @@ -76,7 +76,7 @@ throw new GraphQLError('Invalid input', { source, positions, path, - originalError, + cause, extensions, }); ``` @@ -86,7 +86,9 @@ Each option helps tie the error to specific parts of the GraphQL execution: - `nodes`: The AST nodes associated with the error. - `source` and `positions`: The source document and character offsets. - `path`: The field path leading to the error. -- `originalError`: The underlying JavaScript error, if available. +- `cause`: The underlying JavaScript error or other value, if available. +- `originalError`: The legacy v16 name for an underlying JavaScript error. In + v17 and newer, prefer `cause`. - `extensions`: Any custom metadata you want to include. When a resolver throws an error: @@ -200,4 +202,4 @@ to enforce these best practices consistently. - [GraphQLError reference](https://graphql.org/graphql-js/error/#graphqlerror) - [GraphQL Specification: Error handling](https://spec.graphql.org/October2021/#sec-Errors) - [Apollo Server: Error handling](https://www.apollographql.com/docs/apollo-server/data/errors/) -- [Envelop: Error plugins](https://the-guild.dev/graphql/envelop/plugins/use-error-handler) \ No newline at end of file +- [Envelop: Error plugins](https://the-guild.dev/graphql/envelop/plugins/use-error-handler) diff --git a/website/pages/docs/index.mdx b/website/pages/docs/index.mdx index 9f47a06b32..fde75e5de6 100644 --- a/website/pages/docs/index.mdx +++ b/website/pages/docs/index.mdx @@ -15,10 +15,16 @@ JavaScript and TypeScript. | Version area | Start here | | --- | --- | | Stable v16 API | [v16 API reference](/api-v16/graphql) | -| v17 beta API | [v17 API reference](/api-v17/graphql) | +| v17 release candidate API | [v17 API reference](/api-v17/graphql) | | v16 to v17 changes | [What changed in GraphQL.js v17](/upgrade-guides/v16-v17) | | v17 specification experiments | [Experimental Specification Features](/docs/experimental-specification-features) | -| v17 runtime features | [GraphQL Harness](/docs/graphql-harness), [Abort Signals](/docs/abort-signals), [Execution Hooks](/docs/execution-hooks) | +| v17 runtime features | [GraphQL Harness](/docs/graphql-harness), [Abort Signals](/docs/abort-signals), [Execution Hooks](/docs/execution-hooks), [Node.js tracing channels](/api-v17/graphql#category-diagnostics) | The guides in this section describe GraphQL concepts and GraphQL.js behavior. The API sections document the public exports by package module. + +GraphQL.js v17 also publishes Node.js `node:diagnostics_channel` tracing +events, mainly for application performance monitoring (APM) integrations that +observe parse, validate, execute, subscribe, and resolver lifecycle boundaries. +See the [Diagnostics API reference](/api-v17/graphql#category-diagnostics) for +the channel names and payload shapes. diff --git a/website/pages/upgrade-guides/v16-v17.mdx b/website/pages/upgrade-guides/v16-v17.mdx index 9cc129b875..92395a4e60 100644 --- a/website/pages/upgrade-guides/v16-v17.mdx +++ b/website/pages/upgrade-guides/v16-v17.mdx @@ -8,9 +8,9 @@ import { Callout } from 'nextra/components'; # What Changed in GraphQL.js v17 - GraphQL.js v17 is currently available as `17.0.0-beta.1`. This guide + GraphQL.js v17 is currently available as `17.0.0-rc.0`. This guide describes migration-impacting changes from the v16 stable line to the v17 - beta line. + release-candidate line. GraphQL.js v17 keeps the core programming model: build a schema, parse a @@ -18,7 +18,8 @@ document, validate it, and execute it. Most changes make boundaries more explicit. Stable single-result execution is separate from experimental incremental delivery, input coercion is split from diagnostic validation, and development checks are opt-in. Host integration features such as harnesses, -abort signals, and execution hooks are explicit GraphQL.js runtime APIs. +abort signals, execution hooks, and Node.js tracing channels are explicit +GraphQL.js runtime APIs. ## Reading the Labels @@ -60,9 +61,11 @@ to select the right build. Use public entry points such as `graphql`, `graphql/execution`, `graphql/language`, `graphql/type`, `graphql/utilities`, and `graphql/validation`. -Deep imports into GraphQL.js internals may still work in some environments, but -they are not officially supported. Prefer the public entry points above for -application and library code. +GraphQL.js also exposes files below those package modules through `exports`, so +deep imports can resolve. Treat those deep imports as file-level access rather +than semver-stable API boundaries: GraphQL.js only promises semver +compatibility for the root package and package-module entry points. Prefer the +public entry points above for application and library code. **Breaking change.** The deprecated `graphql/subscription` compatibility subpath is gone. Import subscription APIs from `graphql` or @@ -186,6 +189,14 @@ completion with `completed` entries. Schema setup, directive validation, result shapes, and transport guidance are covered in [Defer and Stream](/docs/defer-stream). +**Behavioral tightening.** Defer/stream validation now tracks named fragment +spreads through the selected operation rather than treating every fragment use +in a document the same way. Subscription operations reject active `@defer` and +`@stream` usage found through named fragments. Root-field restrictions apply +only to mutation and subscription root selections, including through fragments +whose type condition is an interface implemented by the root type. Query root +selections may use incremental delivery. + ### Resolver return values **New stable API.** List fields can resolve to async iterables. This is useful @@ -228,9 +239,9 @@ to work, but TypeScript code that assumed a promise return type must be updated to handle the synchronous path. **Breaking change.** `subscribe()` does not support incremental delivery. If a -fragment is shared between queries and subscriptions, use the `if` argument on -`@defer` or `@stream` to disable incremental behavior in subscription -operations. +fragment is shared between queries and subscriptions, use a variable-backed +`if` argument on `@defer` or `@stream`, or applicable `@skip` and `@include` +directives, to disable incremental behavior in subscription operations. ### Lower-level subscription helpers @@ -296,6 +307,22 @@ work is finished. Resolvers can use `info.getAsyncHelpers()` to make additional work visible to that tracking. See [Execution Hooks](/docs/execution-hooks) for examples. +## Node.js Tracing Channels + +**New stable API.** GraphQL.js v17 publishes lifecycle events on Node.js +`node:diagnostics_channel` tracing channels. These channels are mainly for +application performance monitoring (APM) tools, which can subscribe to channels +such as `graphql:parse`, `graphql:validate`, `graphql:execute`, +`graphql:execute:variableCoercion`, `graphql:execute:rootSelectionSet`, +`graphql:subscribe`, and `graphql:resolve` without changing application +execution code. + +The channels are resolved at module load and no-op on runtimes that do not +provide `node:diagnostics_channel`. GraphQL.js also exports TypeScript context +types for strongly typed subscribers. See the +[Diagnostics API reference](/api-v17/graphql#category-diagnostics) for the +channel names and payload shapes. + ## Input Coercion, Defaults, and Custom Scalars ### Default values @@ -373,17 +400,13 @@ success. That value contains source information and coerced runtime values. + const coerced = variableValues.coerced; ``` -This matters because v17 supports fragment-local variables and more precise -default handling. Passing only the coerced object loses information about where -values came from. +This matters because v17 supports local variables on named fragments and more +precise default handling. Passing only the coerced object loses information +about where values came from. **Breaking change.** `info.variableValues` follows the same model. Use `info.variableValues.coerced` for runtime values inside resolvers. -**Behavioral change.** Resolver argument maps and variable maps may use -null-prototype objects. Use `Object.hasOwn(obj, key)` or direct property access -instead of methods inherited from `Object.prototype`. - **New stable API.** `GraphQLResolveInfo` adds `getAbortSignal()` and `getAsyncHelpers()` for the abort-signal and execution-hook APIs. @@ -462,8 +485,9 @@ the `experimentalFragmentArguments` parser option. Older GraphQL.js versions had an experimental `allowLegacyFragmentVariables` option, but that was parser-only and did not work at runtime. -When enabled, fragment definitions can declare variables and fragment spreads -can pass arguments. See [Fragment Arguments](/docs/fragment-arguments). +When enabled, named fragments can declare local variables and named fragment +spreads can provide values. See +[Fragment Arguments](/docs/fragment-arguments). ## Validation @@ -526,27 +550,144 @@ Pass a message and an options object. + source, + positions, + path, -+ originalError, ++ cause, + extensions, + }); ``` +**Deprecation.** `GraphQLErrorOptions.originalError` and +`GraphQLError.originalError` still exist as a migration bridge, but v17 prefers +the standard `Error.cause` field. Passing `cause` sets `error.cause`; when the +cause is an `Error`, GraphQL.js also exposes it through `originalError` for +compatibility. Unlike `originalError`, a `cause` stack is not copied onto the +`GraphQLError`, because JavaScript tooling can already report cause chains. + ## Practical Migration Order -1. Update Node.js, TypeScript, and package-entry imports. -2. Compile and replace removed helpers, removed alias types, and positional - `GraphQLError` calls. -3. Run `validateSchema()` and migrate invalid or ambiguous defaults to the new - `default` model. -4. Update execution hosts: `execute()` versus - `experimentalExecuteIncrementally()`, `createSourceEventStream()` validation, - and subscription return types. -5. Migrate custom scalars to the v17 coercion method names while keeping the - v16 names if you still support v16. -6. Adopt optional host features such as development mode, harnesses, abort - signals, execution hooks, and fragment arguments only where they match your - server design. +Use this order to keep the upgrade reviewable. The checklists below expand +each category into concrete items. + +1. Update platform support and package-entry imports. +2. Replace APIs that were removed in v17 and update changed AST/type surfaces. +3. Update schema validation, defaults, input coercion, and variable-value + handling. +4. Update execution and subscription hosts, especially incremental-delivery + paths. +5. Migrate deprecated compatibility APIs that still work in v17 but should be + gone before v18. +6. Adopt optional runtime integrations and experimental features only where + they match your server design. Run schema validation, operation validation, execution tests, and TypeScript -checks after each group. The upgrade is easiest to review when mechanical -changes are separated from behavior changes. +checks after each group. Mechanical changes are easiest to review when they are +separated from behavior changes. + +## Detailed Migration Checklists + +### Platform and imports + +- Run v17 on Node.js 22, 24, 25, or 26 and later. +- Keep TypeScript at 4.4 or newer. +- Prefer package-module entry points such as `graphql`, `graphql/execution`, + `graphql/language`, `graphql/type`, `graphql/utilities`, and + `graphql/validation` for semver-stable imports. Audit deep imports below + those modules, since they are exposed but are not semver-stable API + boundaries. +- Replace `graphql/subscription` imports with `graphql` or + `graphql/execution`. +- Enable development mode explicitly in development environments, either with + the `development` package condition or `enableDevMode()`. + +### Removed APIs and required replacements + +- Replace positional `GraphQLError` constructor calls with the options object. +- Replace `KindEnum`, `TokenKindEnum`, and `DirectiveLocationEnum` with `Kind`, + `TokenKind`, and `DirectiveLocation`. +- Replace `getVisitFn()` with `getEnterLeaveForKind()`. +- Remove the custom `TypeInfo` fifth argument to `validate()`; use + `visitWithTypeInfo()` for custom traversals. +- Replace `assertValidName()` and `isValidNameError()` with `assertName()`. +- Replace `assertValidExecutionArguments()` with `assertValidSchema()` or + `validateExecutionArgs()`, depending on whether you are validating a schema + or execution arguments. +- Replace `getOperationRootType()` with `schema.getRootType(operation)`. +- Remove `getFieldDefFn` customizations from `TypeInfo`. +- Replace `printError()` and `formatError()` with `error.toString()` and + `error.toJSON()`. +- Replace `GraphQLInterfaceTypeNormalizedConfig` with + `ReturnType`. +- Treat empty AST collections as optional, because v17 may represent them as + `undefined` rather than empty arrays. + +### Schema, defaults, and input values + +- Run `validateSchema()` and fix invalid argument, input-field, and + directive-argument defaults. +- Prefer `default: { value }` for raw JavaScript input values and + `default: { literal }` for GraphQL literals. +- Update direct `coerceInputValue()` and `coerceInputLiteral()` callers that + expect diagnostic errors; use `validateInputValue()` or + `validateInputLiteral()` when you need errors. +- Use `valueToLiteral()` for converting external JavaScript input values to + GraphQL literals. +- Call `replaceVariables()` before direct scalar literal coercion when a literal + may contain variables outside GraphQL.js execution. +- Update `getVariableValues()` callers to read `result.variableValues.coerced` + instead of `result.coerced`. +- Update resolvers that read `info.variableValues` to use + `info.variableValues.coerced`. + +### Execution and subscriptions + +- Use `execute()` only for stable single-result execution. +- Use `experimentalExecuteIncrementally()` for operations that may use active + `@defer` or `@stream`. +- Remove code that checks the old incremental `singleResult` discriminator. +- Keep `legacyExecuteIncrementally()` only for hosts that still need the older + incremental payload shape. +- Use `validateExecutionArgs()` before lower-level execution helpers such as + `executeRootSelectionSet()`, `experimentalExecuteRootSelectionSet()`, and + `legacyExecuteRootSelectionSet()`. +- Handle `subscribe()` returning either a value or a promise. +- Call `validateSubscriptionArgs()` before `createSourceEventStream()`. +- Replace subscription `perEventExecutor` usage with + `mapSourceToResponseEvent()` and its root-selection-set executor argument. +- Disable incremental behavior in shared subscription fragments with a + variable-backed `if` argument on `@defer` or `@stream`, or applicable `@skip` + and `@include` directives. + +### Deprecated compatibility APIs + +These v16 APIs still work in v17, but are deprecated for removal in v18: + +- Programmatic `defaultValue` on arguments and input fields, including their + config objects; use `default: { value }` or `default: { literal }`. +- `GraphQLScalarType` legacy coercion hooks `serialize`, `parseValue`, and + `parseLiteral`; use `coerceOutputValue`, `coerceInputValue`, and + `coerceInputLiteral`. +- `GraphQLEnumType` legacy coercion methods `serialize()`, `parseValue()`, and + `parseLiteral()`; use `coerceOutputValue()`, `coerceInputValue()`, and + `coerceInputLiteral()`. +- `GraphQLScalarSerializer`, `GraphQLScalarValueParser`, and + `GraphQLScalarLiteralParser`; use `GraphQLScalarOutputValueCoercer`, + `GraphQLScalarInputValueCoercer`, and `GraphQLScalarInputLiteralCoercer`. +- `astFromValue()`; use `valueToLiteral()`. +- `valueFromAST()`; use `coerceInputLiteral()`. +- `findBreakingChanges()` and `findDangerousChanges()`; use + `findSchemaChanges()`. +- `GraphQLErrorOptions.originalError` and `GraphQLError.originalError`; use + `cause`. + +### Optional v17 runtime and experimental features + +- Use `hideSuggestions` when public diagnostics should omit schema suggestions. +- Use `abortSignal` and `info.getAbortSignal()` when a host can propagate + cancellation to downstream work. +- Use `info.getAsyncHelpers()` and `asyncWorkFinished` hooks when a host needs + a cleanup or telemetry boundary after tracked async work settles. +- Use Node.js tracing channels primarily for application performance + monitoring (APM) integrations. +- Consider `GraphQLHarness` when a host needs to customize `graphql()` parse, + validate, execute, or subscribe phases. +- Enable `experimentalFragmentArguments` only for hosts that intentionally + support arguments on named fragment spreads.