# graphql-tools: SDL-first schema building, stitching and mocking for GraphQL

> graphql-tools is a TypeScript monorepo for building executable GraphQL schemas from SDL, merging types and resolvers across files, mocking APIs per type, and stitching several schemas into one. It is a schema layer, not an HTTP server, and the README points elsewhere for that.

**ardatan/graphql-tools** — :wrench: Utility library for GraphQL to build, stitch and mock GraphQL schemas in the SDL-first approach

- Repository: https://github.com/ardatan/graphql-tools
- Website: https://www.graphql-tools.com
- Stars: 5,430 · Forks: 829
- Language: TypeScript
- License: MIT
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/ardatan-graphql-tools

## The problem graphql-tools solves: SDL as the source of truth

Writing a GraphQL schema by hand in GraphQL.js means constructing type objects programmatically. graphql-tools takes the opposite route. The README describes the approach as schema language first: you write the type definitions as a GraphQL string, and the library turns that string plus a resolver map into a runnable schema. The README states the produced schema is completely compatible with GraphQL.js, so anything that accepts a GraphQL.js schema accepts this one.

The intended user is a JavaScript or TypeScript backend developer who already thinks in SDL. The README frames the split of responsibilities plainly: graphql-tools writes the schema and resolver code, and GraphQL Yoga connects it to a web server. If you are looking for a server, a middleware, or a gateway product, this is the wrong layer. It is a library for producing the schema object those other pieces consume.

The repository is a monorepo. The package.json declares workspaces for packages/*, packages/loaders/*, packages/executors/* and website, and the README's own links point at separate documentation pages for generate-schema, mocking, and stitch-combining-schemas. That layout tells you the surface is wider than one import, and that you should read the sub-package you actually need rather than assume a single entry point.

## makeExecutableSchema and the typeDefs/resolvers data flow

The core mechanism in the README example is short. A typeDefs string declares Author, Post, Query and Mutation, with a schema block naming the root query and mutation types. A resolvers object maps type names to field functions: Query.posts returns the list, Mutation.upvotePost takes a postId argument and mutates it, and Author.posts and Post.author resolve relations from the parent object.

makeExecutableSchema takes both and returns the executable schema. From that point the data flow is GraphQL.js's: a query arrives, the executor selects fields, and each field with a resolver calls that function with the parent value and arguments. Fields without resolvers fall back to default property lookup on the parent object, which is why Post.title needs no resolver in the example while Post.author does.

The README notes the example keeps everything in one string and one file, then points to two documentation pages for splitting it up: modularizing type definitions and merging resolvers. That is the real scaling story here. Small schemas fit in one file; anything larger is expected to be assembled from multiple typeDefs and multiple resolver objects, which is where the merge package in the repository layout comes in.

One design consequence worth stating: because resolvers are looked up by type and field name in a plain nested object, a typo in a type name does not fail at import time. It fails when that field is queried. The README does not describe a validation step for resolver keys.

## Installing graphql-tools and building a first schema

The README shows imports from @graphql-tools/schema rather than from a single graphql-tools package, so install the scoped package for the feature you need. The repository is published on npm, as the npm version badge in the README for @graphql-tools/utils indicates.

```bash
npm install @graphql-tools/schema graphql
```

Define the schema as SDL and the resolvers as a nested object. The README's example uses a schema block to name the root types, which is optional when you use the conventional Query and Mutation names, but harmless and explicit.

```js
const typeDefs = /* GraphQL */ `
  type Post {
    id: ID!
    title: String
    votes: Int
  }

  type Query {
    posts: [Post]
  }
`
```

Pass both to makeExecutableSchema. The return value is a GraphQL.js schema object, which is the thing you hand to any consumer.

```js
import { makeExecutableSchema } from '@graphql-tools/schema'

const executableSchema = makeExecutableSchema({
  typeDefs,
  resolvers
})
```

To confirm it works, attach it to an HTTP server. The README gives this exact pattern with GraphQL Yoga and Node's http module, and says the server logs a listening message on port 4000 with the /graphql path.

```js
const { createYoga } = require('graphql-yoga')
const { createServer } = require('http')

const yoga = createYoga({ schema: executableSchema })
const server = createServer(yoga)

server.listen(4000, () => {
  console.log('Yoga is listening at http://localhost:4000/graphql')
})
```

After starting that, a query for posts should return the array your Query.posts resolver produced. If the schema builds but the query returns nulls, the resolver key names are the first thing to check.

## Mocking and stitching: two features that change how you use the library

The README lists three capabilities, and two of them are not about writing production resolvers at all.

Mocking is described as fine-grained per-type mocking. The value here is frontend and test work: you can stand up a schema whose fields return generated values instead of hitting a database, and the granularity is per type, so you can mock one type realistically and let another use defaults. The README does not state which mock data library backs this or how to override a single field, so treat the mocking documentation page as required reading before you plan a test suite around it.

Stitching is the more consequential feature. The README describes it as automatically stitching multiple schemas together into one larger API, and the docs link is titled combining schemas. This is the pattern for a gateway in front of several GraphQL services: each service owns its own schema, and the stitched schema presents one endpoint. The word automatically is doing real work in that sentence, and it is also the source of the main operational risk. A stitched schema is only as coherent as the underlying services, and the README does not discuss what happens when one of them is unavailable or when two services define the same type differently.

Both features share a property worth naming: they are schema transformations, not runtime proxies you can inspect casually. When a stitched query returns an unexpected shape, the failure is in the composition step, and the README offers no debugging guidance for that case.

## Where graphql-tools is the wrong choice

The clearest boundary is the one the README draws itself. If your question is how to expose a GraphQL endpoint over HTTP, this library does not answer it. The README explicitly directs you to GraphQL Yoga for binding a JavaScript GraphQL schema to an HTTP server, and mentions Apollo GraphQL and express-graphql as other frameworks that can consume the schema. Choosing graphql-tools means you still have to choose one of those.

The second boundary is code-first versus SDL-first. graphql-tools is built around writing type definitions as a string. If your team has settled on generating the schema from decorated classes or from a builder API, this library's central mechanism is the thing you are deliberately avoiding, and its merging and stitching features will not integrate cleanly with a schema that was never expressed as SDL.

Third, the README does not document rollback or migration behaviour for schema changes. There is a SECURITY.md and a CONTRIBUTING.md in the repository root, but nothing in the README about versioning your schema, deprecating fields, or recovering from a bad deploy. If you need those guarantees, they come from your deployment tooling, not from this package.

Finally, the README is thin on failure modes generally. It does not describe error handling in resolvers beyond the example throwing a plain Error, and it does not discuss performance characteristics of stitching. That silence is not evidence of a problem, but it does mean you should not assume the documentation has already thought through your edge case.

## How graphql-tools compares to Apollo Server's schema handling

The most direct alternative for many teams is Apollo Server, which also accepts typeDefs and resolvers and produces an executable schema. The difference in approach is packaging. Apollo Server is a server: it owns the HTTP layer, the playground, and the request pipeline, and schema construction is one part of a larger product. graphql-tools is the schema construction and nothing else, which is why the README can hand HTTP off to three different frameworks without contradiction.

That difference matters in two situations. If you want one dependency that answers both how the schema is built and how requests arrive, Apollo Server is the shorter path. If you want to compose schemas from several sources, mock them for tests, or merge SDL fragments across files while keeping the HTTP layer a separate decision, graphql-tools is the more focused tool, and you can still put Apollo in front of the schema it produces.

A second alternative is plain GraphQL.js with programmatic type construction. That gives you complete control and no abstraction, at the cost of writing every type and field by hand. graphql-tools exists precisely to avoid that, and its compatibility claim in the README means switching between the two is not a rewrite of your execution layer.

## Maintenance, releases and the MIT licence

The repository is not archived, and the last push was on 2026-09-22. Recent releases listed for the project run through July 2026, with two on 2026-07-17 and one on 2026-07-08. The maintainer list in the README names five people, four of them affiliated with The Guild.

The monorepo is managed with npm workspaces and changesets: the root package.json declares npm@12.0.1 as the package manager, and the release and version scripts call changeset publish and changeset version. For a consumer this matters mainly as a signal about how versions are cut. Each package under packages/ is versioned and published separately, so upgrading graphql-tools is not one version bump but a set of them, and the scoped package names in your dependency tree are what you actually pin.

Contributing has a cost of its own. The postinstall script runs patch-package, husky install, and several fix scripts for Astro and Yoga typings, which means a fresh clone does more than install dependencies. Building the project uses bob build, and the test suite runs through jest. If you plan to vendor or fork it, budget for that toolchain rather than assuming a plain npm install and npm test.

The licence is MIT, which permits commercial use and modification with the licence and copyright notice retained. That is a description of the licence text, not legal advice; if you are redistributing a modified copy, have your own counsel read the LICENSE file.

## Conclusion

Adopt graphql-tools when your schema is the source of truth and you want one executable schema assembled from SDL, merged across files, or stitched from several services. Do not adopt it expecting an HTTP server: the README hands that job to GraphQL Yoga. Before committing, verify the exact package names you need under packages/ in the monorepo, since the README only documents @graphql-tools/schema by name, and confirm the version of graphql-tools your framework already pins.

## FAQ

### What is graphql-tools used for?

The README lists three uses: generating a schema from the GraphQL schema language with full resolver, interface, union and custom scalar support, mocking a GraphQL API with per-type mocking, and automatically stitching multiple schemas into one larger API. The generated schema is stated to be compatible with GraphQL.js.

### Which package do I install to use graphql-tools?

The README example imports makeExecutableSchema from @graphql-tools/schema, and the npm badge in the README points at @graphql-tools/utils. The repository is a monorepo with workspaces under packages/, packages/loaders/ and packages/executors/, so the package you need depends on the feature.

### Does graphql-tools include an HTTP server?

No. The README states that if you want to bind your JavaScript GraphQL schema to an HTTP server you can use GraphQL Yoga, and describes the two as complementary: graphql-tools writes the schema and resolver code, GraphQL Yoga connects it to a web server. Apollo GraphQL and express-graphql are also named as frameworks that can consume the schema.

### How do I run a graphql-tools schema on a port?

The README passes the schema returned by makeExecutableSchema into createYoga from graphql-yoga, wraps it with createServer from Node's http module, and calls server.listen(4000), logging that Yoga is listening at http://localhost:4000/graphql. The README notes GraphQL Yoga's own documentation covers other JavaScript platforms.

### What licence does graphql-tools use?

The repository is MIT licensed. That permits commercial use and modification provided the licence and copyright notice are retained; the repository root contains a LICENSE file and a SECURITY.md.

## Sources

- [ardatan/graphql-tools on GitHub](https://github.com/ardatan/graphql-tools)
- [License: MIT](https://github.com/ardatan/graphql-tools/blob/master/LICENSE)
- [Project website](https://www.graphql-tools.com)
- [README](https://github.com/ardatan/graphql-tools/blob/master/README.md)
- [Releases](https://github.com/ardatan/graphql-tools/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ardatan-graphql-tools
