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
| 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
+
+
+
+
+ | Name |
+ Type |
+ Description |
+
+
+
+
+ | source |
+ |
+ Source 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
+
+
+
+
+ | Name |
+ Type |
+ Description |
+
+
+
+
+ | schema |
+ |
+ Schema used for validation. |
+
+
+ | document |
+ |
+ Parsed 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
+
+
+
+
+ | Name |
+ Type |
+ Description |
+
+
+
+
+ | schema |
+ |
+ Schema used for execution. |
+
+
+ | document |
+ |
+ Parsed document being executed. |
+
+
+ | rawVariableValues |
+ |
+ Raw variable values provided by the caller before coercion. |
+
+
+ | operationName |
+ |
+ Selected operation name, if one is available. |
+
+
+ | operationType |
+ |
+ Selected 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
+
+
+
+
+ | Name |
+ Type |
+ Description |
+
+
+
+
+ | schema |
+ |
+ Schema used for execution. |
+
+
+ | document |
+ |
+ Parsed document being executed. |
+
+
+ | operation |
+ |
+ Operation definition selected for execution. |
+
+
+ | rawVariableValues |
+ |
+ Raw variable values provided by the caller before coercion. |
+
+
+ | operationName |
+ |
+ Selected operation name, if one is available. |
+
+
+ | operationType |
+ |
+ Selected 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
+
+
+
+
+ | Name |
+ Type |
+ Description |
+
+
+
+
+ | schema |
+ |
+ Schema used for variable coercion. |
+
+
+ | document |
+ |
+ Parsed document being executed. |
+
+
+ | operation |
+ |
+ Operation definition whose variables are being coerced. |
+
+
+ | rawVariableValues |
+ |
+ Raw variable values provided by the caller before coercion. |
+
+
+ | operationName |
+ |
+ Selected operation name, if one is available. |
+
+
+ | operationType |
+ |
+ Selected 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
+
+
+
+
+ | Name |
+ Type |
+ Description |
+
+
+
+
+ | schema |
+ |
+ Schema used for subscription execution. |
+
+
+ | document |
+ |
+ Parsed subscription document. |
+
+
+ | rawVariableValues |
+ |
+ Raw variable values provided by the caller before coercion. |
+
+
+ | operationName |
+ |
+ Selected operation name, if one is available. |
+
+
+ | operationType |
+ |
+ Selected 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
+
+
+
+
+ | Name |
+ Type |
+ Description |
+
+
+
+
+ | fieldName |
+ |
+ Field name being resolved. |
+
+
+ | alias |
+ |
+ Response alias for the field being resolved. |
+
+
+ | parentType |
+ |
+ Parent type name for the field being resolved. |
+
+
+ | fieldType |
+ |
+ Return type string for the field being resolved. |
+
+
+ | args |
+ |
+ Argument values passed to the resolver. |
+
+
+ | isDefaultResolver |
+ |
+ Whether the field is using the default resolver. |
+
+
+ | fieldPath |
+ |
+ Response 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
+
+
+
+
+ | Name |
+ Type |
+ Description |
+
+
+
+
+ | graphql:parse |
+ |
+ Context published on {"graphql:parse"}. |
+
+
+ | graphql:validate |
+ |
+ Context published on {"graphql:validate"}. |
+
+
+ | graphql:execute |
+ |
+ Context published on {"graphql:execute"}. |
+
+
+ | graphql:execute:variableCoercion |
+ |
+ Context published on {"graphql:execute:variableCoercion"}. |
+
+
+ | graphql:execute:rootSelectionSet |
+ |
+ Context published on {"graphql:execute:rootSelectionSet"}. |
+
+
+ | graphql:subscribe |
+ |
+ Context published on {"graphql:subscribe"}. |
+
+
+ | graphql:resolve |
+ |
+ Context 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
+
+
+
+
+ | Name |
+ Type |
+ Description |
+
+
+
+
+ | execute |
+ |
+ Tracing channel for {"graphql:execute"}. |
+
+
+ | executeVariableCoercion |
+ |
+ Tracing channel for {"graphql:execute:variableCoercion"}. |
+
+
+ | executeRootSelectionSet |
+ |
+ Tracing channel for {"graphql:execute:rootSelectionSet"}. |
+
+
+ | parse |
+ |
+ Tracing channel for {"graphql:parse"}. |
+
+
+ | validate |
+ |
+ Tracing channel for {"graphql:validate"}. |
+
+
+ | resolve |
+ |
+ Tracing channel for {"graphql:resolve"}. |
+
+
+ | subscribe |
+ |
+ Tracing 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.