graphql-tools vs apollo-server vs express-graphql
GraphQL Server Implementation and Schema Management in Node.js
graphql-toolsapollo-serverexpress-graphqlSimilar Packages:

GraphQL Server Implementation and Schema Management in Node.js

apollo-server, express-graphql, and graphql-tools are foundational packages in the Node.js GraphQL ecosystem, each serving distinct but sometimes overlapping roles. apollo-server is a standalone GraphQL server implementation that includes built-in support for Express and other web frameworks, offering features like schema stitching, subscriptions, and developer tooling. express-graphql is a minimal middleware that adds GraphQL execution to an existing Express application, relying on the core graphql package for query resolution. graphql-tools provides utilities for constructing and manipulating GraphQL schemas programmatically, notably through the makeExecutableSchema function, and is often used alongside server implementations to define resolvers and type definitions cleanly.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
graphql-tools860,8575,4202.61 kB1572 months agoMIT
apollo-server237,45413,95026.6 kB792 years agoMIT
express-graphql06,291-555 years agoMIT

Building GraphQL Servers in Node.js: apollo-server vs express-graphql vs graphql-tools

When setting up a GraphQL API in Node.js, developers often encounter three key packages: apollo-server, express-graphql, and graphql-tools. While they all relate to GraphQL, they serve different purposes—one is a full server, one is a lightweight middleware, and one is a schema utility library. Understanding their roles prevents architectural missteps, especially since one of them is no longer maintained.

⚠️ Deprecation Status: Know Before You Build

First, a critical update: express-graphql is officially deprecated. The npm page states: "This package is no longer maintained. We recommend using Apollo Server instead." This means you should not use express-graphql in new projects. We include it here only for context and migration guidance.

In contrast, both apollo-server and graphql-tools are actively maintained and widely used in production systems.

🧱 Core Responsibilities: What Each Package Actually Does

apollo-server: Full-Featured GraphQL Server

apollo-server is a complete GraphQL server implementation. It handles HTTP requests, parses queries, executes resolvers, formats errors, and serves GraphQL Playground (in development). It can run standalone or integrate with Express, Koa, Hapi, and more.

// apollo-server: Standalone server
import { ApolloServer } from 'apollo-server';
import { typeDefs, resolvers } from './schema.js';

const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => console.log(`Server ready at ${url}`));

express-graphql: Minimal Express Middleware (Deprecated)

express-graphql is just a middleware that plugs GraphQL execution into an Express app. It delegates almost everything to the graphql package and offers minimal configuration.

// express-graphql: Deprecated usage
import express from 'express';
import { graphqlHTTP } from 'express-graphql';
import { schema } from './schema.js';

const app = express();
app.use('/graphql', graphqlHTTP({ schema, graphiql: true }));
app.listen(4000);

🔴 Do not use this in new code. Migrate to Apollo Server if you're maintaining an old codebase.

graphql-tools: Schema Construction Utilities

graphql-tools doesn’t run a server—it helps you build schemas. Its flagship function, makeExecutableSchema, combines type definitions (SDL) and resolver objects into a single executable schema object that any GraphQL server can use.

// graphql-tools: Schema creation
import { makeExecutableSchema } from 'graphql-tools';

const typeDefs = `
  type Query {
    hello: String
  }
`;

const resolvers = {
  Query: { hello: () => 'Hello world!' }
};

const schema = makeExecutableSchema({ typeDefs, resolvers });
// Now pass `schema` to Apollo Server, Yoga, or any other server

🛠️ Real-World Integration Patterns

Using graphql-tools with apollo-server

Most professional Apollo Server setups use graphql-tools under the hood (even if indirectly). Here’s how they work together:

// Combined: graphql-tools + apollo-server
import { ApolloServer } from 'apollo-server';
import { makeExecutableSchema } from 'graphql-tools';

const schema = makeExecutableSchema({
  typeDefs: `type Query { user(id: ID!): User } type User { id: ID! name: String }`,
  resolvers: {
    Query: { user: (_, { id }) => ({ id, name: 'Alice' }) }
  }
});

const server = new ApolloServer({ schema });
server.listen();

Note: Modern Apollo Server versions accept typeDefs and resolvers directly and internally use graphql-tools, so explicit makeExecutableSchema isn’t always needed—but it’s still useful for advanced cases like schema merging.

Why Not Use express-graphql Today?

Beyond deprecation, express-graphql lacks:

  • Built-in support for GraphQL subscriptions
  • File upload handling
  • Structured error formatting
  • Plugin system for observability
  • Security features like depth limiting

Apollo Server provides all these out of the box.

🧩 Advanced Schema Workflows with graphql-tools

Where graphql-tools shines is in complex schema management:

Schema Stitching (Legacy Federation)

Before Apollo Federation, graphql-tools enabled combining multiple GraphQL services into one schema:

import { stitchSchemas } from 'graphql-tools';

const gatewaySchema = stitchSchemas({
  subschemas: [
    { schema: userServiceSchema },
    { schema: orderServiceSchema }
  ]
});

Note: For new microservices, use Apollo Federation instead—but graphql-tools still powers many stitching-based systems.

Mocking for Development

Generate realistic mock data from your schema:

import { addMocksToSchema } from 'graphql-tools';

const mockedSchema = addMocksToSchema({ schema });
// Now all resolvers return auto-generated mock data

This is invaluable for frontend teams working before backend APIs are ready.

🔒 Error Handling and Developer Experience

Apollo Server

Provides structured error formatting, masking stack traces in production, and extension points:

const server = new ApolloServer({
  formatError: (err) => ({
    message: err.message,
    code: err.extensions?.code || 'INTERNAL_ERROR'
  })
});

express-graphql (Deprecated)

Offers basic error handling but no customization hooks beyond a global formatError option.

graphql-tools

Not applicable—it doesn’t handle runtime execution, so no error formatting.

📦 When to Use Which: Practical Guidance

ScenarioRecommended Package(s)
New GraphQL API from scratchapollo-server (with or without explicit graphql-tools)
Need modular schema design or mockinggraphql-tools + any server (e.g., Apollo Server)
Maintaining old Express app with GraphQLMigrate from express-graphql to apollo-server-express
Building a GraphQL gatewayUse @apollo/server with Federation, not graphql-tools stitching

💡 Key Takeaways

  • apollo-server is your go-to for production GraphQL servers—feature-rich, secure, and well-supported.
  • express-graphql is deprecated. Avoid it in new projects; plan to migrate existing uses.
  • graphql-tools is not a server—it’s a toolkit for schema authoring, testing, and composition. It complements server libraries rather than replacing them.

In modern architectures, you’ll often see apollo-server and graphql-tools used together: the former runs the API, the latter builds the schema. Understanding this division of labor leads to cleaner, more maintainable GraphQL implementations.

How to Choose: graphql-tools vs apollo-server vs express-graphql

  • graphql-tools:

    Choose graphql-tools when you need flexible, programmatic schema construction—especially for modular schema design, schema merging, or mock generation—without tying yourself to a specific server implementation. It pairs well with any GraphQL server (including Apollo Server) and is essential for advanced schema workflows like federation or testing.

  • apollo-server:

    Choose apollo-server if you need a production-ready, batteries-included GraphQL server with integrated tooling like Apollo Studio, persisted queries, and built-in support for subscriptions and file uploads. It’s ideal for teams building full-featured GraphQL APIs who want conventions, security defaults, and extensibility without assembling low-level pieces manually.

  • express-graphql:

    Choose express-graphql only if you’re maintaining a legacy Express app that already uses this middleware and you need minimal GraphQL integration without additional dependencies. Note that it is officially deprecated and should not be used in new projects — consider migrating to Apollo Server or another modern alternative.

README for graphql-tools

ERROR: No README data found!