NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #3292 most downloaded on npm
A set of utils for faster development of GraphQL tools
Last release 28 days ago
08 Sep 2026
Ships fairly regularly
a new release about every 2 weeks
Nearly every release is documented
notes for 59 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
6 years old
3654 releases · first in 2020
One column per quarter.
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Previously we were applying the transforms multiple times. We needed to introduced some breaking changes to improve the initial wrapped/stitched schem…
#6134
a83da08
Thanks @User! - Ignore unmerged fields
Let's say you have a gateway schema like in the bottom, and id is added to the query, only if
the age is requested;
# This will be sent as-is
{
user {
name
}
}
But the following will be transformed;
{
user {
name
age
}
}
Into
{
user {
id
name
age
}
}
```graphql
type Query {
}
type User {
id: ID! # is the key for all services
name: String!
age: Int! # This comes from another service
}
#6150
fc9c71f
Thanks @ardatan! - If there are some fields depending on a nested
type resolution, wait until it gets resolved then resolve the rest.
See packages/federation/test/fixtures/complex-entity-call example for more details. You can see
ProductList needs some fields from Product to resolve first
#6126
680351e
Thanks @ardatan! - When there is a Node subschema, and others to
resolve the rest of the entities by using a union resolver as in Federation like below, it was
failing. This version fixes that issue.
query {
node(id: "1") {
id # Fetches from Node
... on User {
name # Fetches from User
}
}
}
type Query {
node(id: ID!): Node
}
interface Node {
id: ID!
}
type User implements Node {
id: ID!
}
type Post implements Node {
id: ID!
}
# User subschema
scalar _Any
type Query {
_entities(representations: [_Any!]!): [_Entity]!
}
union _Entity = User
interface Node {
id: ID!
}
type User implements Node {
id: ID!
name: String!
}
# Post subschema
scalar _Any
union _Entity = Post
type Query {
_entities(representations: [_Any!]!): [_Entity]!
}
interface Node {
id: ID!
}
type Post implements Node {
id: ID!
title: String!
}
af7be09
Thanks @ardatan! - Hotfix: do not use nullable and nonNullable
prefixes if field names don't match#6091
9bca9e0
Thanks @User, @User! - If the gateway
receives a query with an overlapping fields for the subschema, it uses aliases to resolve it
correctly.
Let's say subschema A has the following schema;
type Query {
}
interface User {
id: ID!
name: String!
}
type Admin implements User {
id: ID!
name: String!
role: String!
}
type Customer implements User {
id: ID!
name: String
email: String
}
And let's say the gateway has the following schema instead;
type Query {
}
interface User {
id: ID!
name: String!
}
type Admin implements User {
id: ID!
name: String!
role: String!
}
type Customer implements User {
id: ID!
name: String!
email: String!
}
In this case, the following query is fine for the gateway but for the subschema, it's not;
query {
user {
... on Admin {
id
name # This is nullable in the subschema
role
}
... on Customer {
id
name # This is non-nullable in the subschema
email
}
}
}
So the subgraph will throw based on this rule OverlappingFieldsCanBeMerged
To avoid this, the gateway will use aliases to resolve the query correctly. The query will be transformed to the following;
query {
user {
... on Admin {
id
name # This is nullable in the subschema
role
}
... on Customer {
id
name: _nullable_name # This is non-nullable in the subschema
email
}
}
}
#6092
243c353
Thanks @ardatan! - If one of the subgraphs are already able to
resolve a nested field as in parent-entity-call example's Category.details from C's Product,
resolve it from there instead of using type merging.
query {
product {
category {
details {
# This is coming from C's Product, so resolve it from there instead of Type Merging
id
name
}
}
}
}
#5913
83c0af0
Thanks @enisdenjo! - dependencies updates:
@graphql-tools/schema@^10.0.2 ↗︎
(from ^10.0.0, in dependencies)@graphql-tools/utils@^10.0.13 ↗︎
(from ^10.0.5, in dependencies)#5913
83c0af0
Thanks @enisdenjo! - No unnecessary inline fragment spreads for
union types
Updated dependencies
[83c0af0,
83c0af0,
83c0af0]:
#5477
cfd47827
Thanks @ardatan! - dependencies updates:
value-or-promise@^1.0.12 ↗︎ (from
dependencies)a59fb765
Thanks @ardatan! - Optimizations to get better performance in query
planning
Updated dependencies
[a59fb765]:
Updated dependencies
[944a68e8,
944a68e8]:
Updated dependencies
[88244048,
8e80b689]:
2f342e43
Thanks @ardatan! - Do not use promises if not async
Updated dependencies
[2f342e43]:
05c97eb8,
05c97eb8,
05c97eb8,
f24f018a]:
91a895be]:
1c95368a]:
828fbf93]:
f26392a6
Thanks @neumark! - Create symbols with Symbol.for() because multiple
copies of delegate cause stitching bugs otherwise.492220cb
Thanks @n1ru4l! - dependencies updates:
@graphql-tools/batch-execute@^8.5.18 ↗︎
(from 8.5.18, in dependencies)@graphql-tools/executor@^0.0.14 ↗︎
(from 0.0.14, in dependencies)@graphql-tools/schema@^9.0.16 ↗︎
(from 9.0.16, in dependencies)@graphql-tools/utils@^9.2.1 ↗︎
(from 9.2.1, in dependencies)dataloader@^2.2.2 ↗︎
(from 2.2.2, in dependencies)tslib@^2.5.0 ↗︎ (from
~2.5.0, in dependencies)value-or-promise@^1.0.12 ↗︎ (from
1.0.12, in dependencies)77c1002e]:
30bd4d0c
Thanks @renovate! - dependencies updates:
dataloader@2.2.2 ↗︎
(from 2.2.1, in dependencies)30bd4d0c]:
b09ea282
Thanks @renovate! - dependencies updates:
dataloader@2.2.1 ↗︎
(from 2.1.0, in dependencies)b09ea282,
b5c8f640]:
a94217e9,
62d074be]:
772b948a
Thanks @renovate! - dependencies updates:
tslib@~2.5.0 ↗︎ (from
~2.4.0, in dependencies)a4d36fcc
Thanks @renovate! - dependencies updates:
value-or-promise@1.0.12 ↗︎ (from
1.0.11, in dependencies)a4d36fcc,
a4d36fcc,
a4d36fcc,
e3ec35ed]:
13177794
Thanks @ardatan! - Handle type merging with union types correctly ->
See https://github.com/ardatan/graphql-tools/issues/4902#4890
eb6cd8b6
Thanks @ardatan! - Transform provided argument values properly
#4890
eb6cd8b6
Thanks @ardatan! - Handle argument definitions correctly during
delegation and transformations
Updated dependencies
[904fe770]:
13c24883
Thanks @ardatan! - Fix handling argument values in gateway request
b5e6459f
Thanks @ardatan! - Show warning only if DEBUG env var is present
Updated dependencies
[13c24883]:
7411a5e7]:
1d3856dc]:
c0639dd0]:
d83b1960]:
f47f3559]:
#4796
80836fa7
Thanks @saihaj! - update collectFields to support collecting
deffered values
Updated dependencies
[80836fa7,
80836fa7,
8f6d3efc,
80836fa7,
80836fa7,
80836fa7,
80836fa7]:
f7daf777]:
df5848b8
Thanks @saihaj! - dependencies updates:
@graphql-tools/executor@0.0.0 ↗︎
(to dependencies)df5848b8,
df5848b8,
df5848b8,
df5848b8]:
00c4a1a4
Thanks @ardatan! - If type is a list but the provided value isn't,
do not fail and resolve that value as the member of that list type43c736bd]:
71cb4fae,
403ed450]:
4fe3d9c0]:
2609d71f]:
#4566
d8dc67aa
Thanks @ardatan! - ## Breaking changes
Schema generation optimization by removing transfomedSchema parameter
Previously we were applying the transforms multiple times. We needed to introduced some breaking changes to improve the initial wrapped/stitched schema generation performance;
Transform.transformSchema no longer accepts transformedSchema which can easily be created
with applySchemaTransforms(schema, subschemaConfig) instead.createProxyingResolver to
SubschemaConfig no longer takes transformedSchema which can easily be created with
applySchemaTransforms(schema, subschemaConfig) instead.stitchSchemas doesn't take nested arrays of subschemas
stitchSchemas no longer accepts an array of arrays of subschema configuration objects. Instead,
it accepts an array of subschema configuration objects or schema objects directly.
stitchSchemas no longer prunes the schema with pruningOptions
You can use pruneSchema from @graphql-tools/utils to prune the schema instead.
stitchSchemas no longer respect "@computed" directive if stitchingDirectivesTransformer isn't
applied
Also @graphql-tools/stitch no longer exports computedDirectiveTransformer and
defaultSubschemaConfigTransforms. Instead, use @graphql-tools/stitching-directives package for
@computed directive.
Learn more about setting it up
computedFields has been removed from the merged type configuration
MergeTypeConfig.computedFields setting has been removed in favor of new computed field
configuration written as:
merge: {
MyType: {
fields: {
myComputedField: {
selectionSet: '{ weight }',
computed: true,
}
}
}
}
A field-level selectionSet specifies field dependencies while the computed setting structures
the field in a way that assures it is always selected with this data provided. The selectionSet
is intentionally generic to support possible future uses. This new pattern organizes all
field-level configuration (including canonical) into a single structure.
#4624
e3167edc
Thanks @n1ru4l! - Fix CommonJS TypeScript resolution with
moduleResolution node16 or nodenext
Updated dependencies
[8cc8721f,
e3167edc]:
26e4b464: relax subschema error path check
...as (apparently) some implementations may return path as null rather than not returning a
path.
0bbb1769: Refine generic typings using extends X when appropriate
Typescript 4.7 has stricter requirements around generics which is explained well in the related PR: https://github.com/microsoft/TypeScript/pull/48366
These changes resolve the errors that these packages will face when attempting to upgrade to TS 4.7 (still in beta at the time of writing this). Landing these changes now will allow other TS libraries which depend on these packages to experiment with TS 4.7 in the meantime.
Updated dependencies [0bbb1769]
631b11bd: refactor(delegationPlanner): introduce static version of our piecemeal planner
...which, although undocumented, can be accessed within the StitchingInfo object saved in a stitched schema's extensions.
Also improves memoization technique slightly across the board.
7d3e3006: BREAKING CHANGE
rootValue from subschemaConfigExecutionParams or delegation optionsinfo.rootValue if rootValue is falsyd53e3be5: BREAKING CHANGES;
Refactor the core delegation transforms into individual functions to modify request and results. This will improve the performance considerably by reducing the number of visits over the request document.
CheckResultAndHandleErrors with checkResultAndHandleErrorsdelegationBindingsAddArgumentsAsVariables, AddSelectionSets, AddTypenameToAbstract,
ExpandAbstractTypes, FilterToSchema, VisitSelectionSets and WrapConcreteTypes with
prepareGatewayDocument and finalizeGatewayRequestdae6dc7b: refactor: ExecutionParams type replaced by Request type
rootValue property is now a part of the Request type.
When delegating with delegateToSchema, rootValue can be set multiple ways:
When using wrapSchema/stitchSchemas, a subschemaConfig can specify the createProxyingResolver function which can pass whatever rootValue it wants to delegateToSchema as above.
c42e811d: BREAKING CHANGES;
Request to ExecutionRequestoperationType: OperationTypeNode field in ExecutionRequestcontext in createRequest and createRequestInfo instead of delegateToSchemaIt doesn't rely on info.operation.operationType to allow the user to call an operation from different root type. And it doesn't call getOperationAST again and again to get operation type from the document/operation because we have it in Request and ExecutionParams https://github.com/ardatan/graphql-tools/pull/3166/files#diff-d4824895ea613dcc1f710c3ac82e952fe0ca12391b671f70d9f2d90d5656fdceR38
Improvements;
defaultExecutor for a single GraphQLSchema so allow getBatchingExecutor to memoize
batchingExecutor correctly.defaultExecutor is created for subscription and other operation
types. Only one executor is used.Batch executor is memoized by
executorreference butcreateDefaultExecutordidn't memoize the default executor so this memoization wasn't working correctly onbatch-executeside. https://github.com/ardatan/graphql-tools/blob/remove-info-executor/packages/batch-execute/src/getBatchingExecutor.ts#L9
7d3e3006: BREAKING CHANGE
AggregateError
implementation. The major difference is the individual errors are kept under errors property
instead of the object itself with Symbol.iterator.// From;
for (const error of aggregateError)
// To;
for (const error of aggregateError.errors)
aa43054d: BREAKING CHANGE: validations are skipped by default, use validateRequest: true to reenable
c0ca3190: BREAKING CHANGE
Executor can receive AsyncIterable and subscriptions will also be handled by
Executor. This is a future-proof change for defer, stream and live queries6aed1714: Allows MergedTypeConfig to be written with an entryPoints array for multiple merged
type entry points, each with their own fieldName and selectionSet:
{
schema: testSchema,
merge: {
Product: {
entryPoints: [{
selectionSet: '{ id }',
fieldName: 'productById',
key: ({ id, price, weight }) => ({ id, price, weight }),
argsFromKeys: (key) => ({ key }),
}, {
selectionSet: '{ upc }',
fieldName: 'productByUpc',
key: ({ upc, price, weight }) => ({ upc, price, weight }),
argsFromKeys: (key) => ({ key }),
}],
}
}
}
These multiple entry points accommodate types with multiple keys across services that rely on a central service to join them, for example:
type Product { upc }type Product { upc id }type Product { id }Given this graph, the possible traversals require the Vendors service to provide entry points for each unique key format:
Catalog > Vendors > ReviewsCatalog < Vendors > ReviewsCatalog < Vendors < ReviewsIs it highly recommended that you enable query batching for subschemas with multiple entry points.
24926654: Deprecates the MergeTypeConfig.computedFields setting (with backwards-compatible
warning) in favor of new computed field configuration written as:
merge: {
MyType: {
fields: {
myComputedField: {
selectionSet: '{ weight }',
computed: true,
}
}
}
}
A field-level selectionSet specifies field dependencies while the computed setting structures
the field in a way that assures it is always selected with this data provided. The selectionSet
is intentionally generic to support possible future uses. This new pattern organizes all
field-level configuration (including canonical) into a single structure.
cd5da458: fix(stitch): type merging for nested root types
Because root types do not usually require selectionSets, a nested root type proxied to a remote service may end up having an empty selectionSet, if the nested root types only includes fields from a different subservice.
Empty selection sets return null, but, in this case, it should return an empty object. We can force this behavior by including the __typename field which exists on every schema.
Addresses #2347.
In the future, we may want to include short-circuiting behavior that when delegating to composite fields, if an empty selection set is included, an empty object is returned rather than null. This short-circuiting behavior would be complex for lists, as it would be unclear the length of the list...
cd5da458: fix(delegate): resolve external values only once
Because items in a list may be identical and the defaultMergedResolver mutates those objects when resolving them as external values, a check is required so that the mutation happens only once.
Partially addresses #2304
Updated dependencies [cd5da458]
718eda30: fix(stitch): fix mergeExternalObject regressions
v7 introduced a regression in the merging of ExternalObjects that causes type merging to fail when undergoing multiple rounds of merging.
arguments being undefinedbe1a1575: ## Breaking Changes:
@graphql-tools/schema)Resolver validation options should now be set to error, warn or ignore rather than true
or false. In previous versions, some of the validators caused errors to be thrown, while some
issued warnings. This changes brings consistency to validator behavior.
The allowResolversNotInSchema has been renamed to requireResolversToMatchSchema, to
harmonize the naming convention of all the validators. The default setting of
requireResolversToMatchSchema is error, matching the previous behavior.
delegateToSchema & @graphql-tools/delegate)The delegateToSchema return value has matured and been formalized as an ExternalObject, in
which all errors are integrated into the GraphQL response, preserving their initial path. Those
advanced users accessing the result directly will note the change in error handling. This also
allows for the deprecation of unnecessary helper functions including slicedError, getErrors,
getErrorsByPathSegment functions. Only external errors with missing or invalid paths must
still be preserved by annotating the remote object with special properties. The new
getUnpathedErrors function is therefore necessary for retrieving only these errors. Note also
the new annotateExternalObject and mergeExternalObjects functions, as well as the renaming
of handleResult to resolveExternalValue.
Transform types and the applySchemaTransforms are now relocated to the delegate package;
applyRequestTransforms/applyResultTransforms functions have been deprecated, however, as
this functionality has been replaced since v6 by the Transformer abstraction.
The transformRequest/transformResult methods are now provided additional delegationContext
and transformationContext arguments -- these were introduced in v6, but previously optional.
The transformSchema method may wish to create additional delegating resolvers and so it is now
provided the subschemaConfig and final (non-executable) transformedSchema parameters. As in
v6, the transformSchema is kicked off once to produce the non-executable version, and then, if
a wrapping schema is being generated, proxying resolvers are created with access to the
(non-executable) initial result. In v7, the individual transformSchema methods also get access
to the result of the first run, if necessary, they can create additional wrapping schema
proxying resolvers.
applySchemaTransforms parameters have been updated to match and support the transformSchema
parameters above.
wrapSchema, makeRemoteExecutableSchema, and @graphql-tools/wrap)wrapSchema and generateProxyingResolvers now only take a single options argument with named
properties of type SubschemaConfig. The previously possible shorthand version with first
argument consisting of a GraphQLSchema and second argument representing the transforms should
be reworked as a SubschemaConfig object.
Similarly, the ICreateProxyingResolverOptions interface that provides the options for the
createProxyingResolver property of SubschemaConfig options has been adjusted. The schema
property previously could be set to a GraphQLSchema or a SubschemaConfig object. This
property has been removed in favor of a subschemaConfig property that will always be a
SubschemaConfig object. The transforms property has been removed; transforms should be
included within the SubschemaConfig object.`
The format of the wrapping schema has solidified. All non-root fields are expected to use
identical resolvers, either defaultMergedResolver or a custom equivalent, with root fields
doing the hard work of proxying. Support for custom merged resolvers throught
createMergedResolver has been deprecated, as custom merging resolvers conflicts when using
stitching's type merging, where resolvers are expected to be identical across subschemas.
The WrapFields transform's wrappingResolver option has been removed, as this complicates
multiple wrapping layers, as well as planned functionality to wrap subscription root fields in
potentially multiple layers, as the wrapping resolvers may be different in different layers.
Modifying resolvers can still be performed by use of an additional transform such as
TransformRootFields or TransformObjectFields.
The ExtendSchema transform has been removed, as it is conceptually simpler just to use
stitchSchemas with one subschema.
The ReplaceFieldsWithFragment, AddFragmentsByField, AddSelectionSetsByField, and
AddMergedTypeSelectionSets transforms has been removed, as they are superseded by the
AddSelectionSets and VisitSelectionSets transforms. The AddSelectionSets purposely takes
parsed SDL rather than strings, to nudge end users to parse these strings at build time (when
possible), rather than at runtime. Parsing of selection set strings can be performed using the
parseSelectionSet function from @graphql-tools/utils.
stitchSchemas & @graphql-tools/stitch)stitchSchemas's mergeTypes option is now true by default! This causes the onTypeConflict
option to be ignored by default. To use onTypeConflict to select a specific type instead of
simply merging, simply set mergeTypes to false.
schemas argument has been deprecated, use subschemas, typeDefs, or types, depending on
what you are stitching.
When using batch delegation in type merging, the argsFromKeys function is now set only via the
argsFromKeys property. Previously, if argsFromKeys was absent, it could be read from args.
Support for fragment hints has been removed in favor of selection set hints.
stitchSchemas now processes all GraphQLSchema and SubschemaConfig subschema input into new
Subschema objects, handling schema config directives such aso@computed as well as generating
the final transformed schema, stored as the transformedSchema property, if transforms are
used. Signatures of the onTypeConflict, fieldConfigMerger, and inputFieldConfigMerger have
been updated to include metadata related to the original and transformed subschemas. Note the
property name change for onTypeConflict from schema to subschema.
addMocksToSchema and @graphql-tools/mock)args, context, and info
with parent available as this rather than as the first argument.@graphql-tools/utils)filterSchema's fieldFilter will now filter all fields across Object, Interface, and Input
types. For the previous Object-only behavior, switch to the objectFieldFilter option.fieldNodes utility functions have been removed.typeContainsSelectionSet function has been removed, and typesContainSelectionSet has
been moved to the stitch package.Operation type has been removed in favor of OperationTypeNode from upstream
graphql-js.applySchemaTransforms/applyRequestTransforms/applyResultTransforms have been
removed from the utils package, as they are implemented elsewhere or no longer necessary.Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →