apollo-server-express vs express-graphql
GraphQL Server Middleware for Express.js
apollo-server-expressexpress-graphqlSimilar Packages:
GraphQL Server Middleware for Express.js

apollo-server-express and express-graphql are both npm packages that enable serving GraphQL APIs over HTTP using the Express.js web framework. They act as middleware layers that parse incoming GraphQL requests, execute them against a provided schema, and return properly formatted JSON responses. While they serve the same fundamental purpose, they differ significantly in feature set, developer experience, and current maintenance status.

Npm Package Weekly Downloads Trend
3 Years
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
apollo-server-express406,16813,93527.6 kB782 years agoMIT
express-graphql175,3906,286-555 years agoMIT

Apollo Server Express vs express-graphql: Building GraphQL APIs in Express

Both apollo-server-express and express-graphql let you add a GraphQL endpoint to an Express.js application. They handle the core job of parsing incoming GraphQL queries, executing them against your schema, and returning structured JSON responses. But they differ significantly in features, flexibility, and current maintenance status. Let’s compare how they work in real projects.

⚠️ Maintenance Status: Active vs Deprecated

express-graphql is officially deprecated. The npm page states: "This package is no longer maintained. We recommend you use Apollo Server instead." The GitHub repository is archived, and no new features or fixes are being accepted.

// ❌ Do not use in new projects
const graphqlHTTP = require('express-graphql');

apollo-server-express is actively maintained as part of the Apollo Server ecosystem. It receives regular updates, security patches, and integrates with modern GraphQL tooling like Apollo Studio.

// ✅ Actively maintained
const { ApolloServer } = require('apollo-server-express');

💡 Bottom line: For any new project, express-graphql should be ruled out immediately due to deprecation.

🧱 Core Setup: Schema and Server Wiring

Both packages require a GraphQL schema, but their setup patterns differ.

express-graphql uses middleware that attaches directly to an Express app:

// express-graphql setup
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { buildSchema } = require('graphql');

const schema = buildSchema(`
  type Query {
    hello: String
  }
`);

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

apollo-server-express uses a class-based server that must be started after Express middleware is applied:

// apollo-server-express setup
const express = require('express');
const { ApolloServer, gql } = require('apollo-server-express');

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

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

async function startServer() {
  const app = express();
  const server = new ApolloServer({ typeDefs, resolvers });
  await server.start();
  server.applyMiddleware({ app });
  app.listen(4000);
}
startServer();

🔍 Developer Experience: Built-in Tooling

express-graphql includes GraphiQL (a basic GraphQL IDE) via the graphiql: true option. That’s about it for DX features.

// express-graphql: enable GraphiQL
app.use('/graphql', graphqlHTTP({ schema, graphiql: true }));

apollo-server-express offers Apollo Sandbox — a modern, feature-rich GraphQL IDE — enabled by default in development. It also supports persisted queries, query validation rules, and plugin hooks.

// apollo-server-express: Sandbox is on by default
// No extra config needed in dev mode
const server = new ApolloServer({ typeDefs, resolvers });

🛠️ Error Handling and Formatting

express-graphql returns raw GraphQL errors in the response. You can customize formatting with a formatError function, but it’s limited.

// express-graphql error formatting
app.use('/graphql', graphqlQHTTP({
  schema,
  formatError: (error) => ({
    message: error.message,
    code: error.originalError?.code
  })
}));

apollo-server-express provides structured error handling through plugins and the formatError option, with better support for masking internal errors in production.

// apollo-server-express error formatting
const server = new ApolloServer({
  typeDefs,
  resolvers,
  formatError: (error) => {
    // Don't expose internal details in prod
    return process.env.NODE_ENV === 'production'
      ? { message: 'Internal server error' }
      : error;
  }
});

📦 Advanced Features: What’s Included?

express-graphql is minimal by design. It does one thing: run GraphQL queries. No built-in support for subscriptions, file uploads, caching hints, or tracing.

apollo-server-express includes many production-ready features out of the box:

  • Subscriptions (via WebSocket)
  • File uploads (with graphql-upload integration)
  • Automatic persisted queries
  • Usage reporting to Apollo Studio
  • Response caching with cacheControl

Example: enabling caching hints in Apollo Server:

// apollo-server-express: cache control
const resolvers = {
  Query: {
    post: (parent, args, context, info) => {
      info.cacheControl.setCacheHint({ maxAge: 60 });
      return getPost(args.id);
    }
  }
};

express-graphql has no equivalent.

🔒 Security and Validation

Both allow custom validation rules, but apollo-server-express makes it easier to apply them consistently and integrates with Apollo Studio for query depth/complexity analysis.

// apollo-server-express: custom validation
const { depthLimit } = require('graphql-depth-limit');

const server = new ApolloServer({
  typeDefs,
  resolvers,
  validationRules: [depthLimit(5)]
});

In express-graphql, you’d pass validationRules to the middleware options, but without tooling support, it’s harder to monitor effectiveness.

🔄 Context and Request Integration

Both support passing request-specific data (like user info) via context.

express-graphql:

app.use('/graphql', graphqlHTTP({
  schema,
  context: ({ req }) => ({
    user: req.user
  })
}));

apollo-server-express:

const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: ({ req }) => ({
    user: req.user
  })
});

The pattern is nearly identical, so this isn’t a differentiator.

🧪 Testing and Mocking

apollo-server-express provides utilities like createTestClient for easy unit testing of resolvers.

// apollo-server-express: testing
const { createTestClient } = require('apollo-server-testing');
const server = new ApolloServer({ typeDefs, resolvers });
const { query } = createTestClient(server);
const res = await query({ query: '{ hello }' });

express-graphql has no official testing helpers—you’d need to mock Express requests manually.

📊 Summary: Key Differences

Featureexpress-graphqlapollo-server-express
Maintenance Status❌ Deprecated✅ Actively maintained
Built-in IDEGraphiQL (basic)Apollo Sandbox (modern)
Subscriptions❌ Not supported✅ Supported
File Uploads❌ Manual implementation✅ Built-in
Caching / Tracing❌ None✅ CacheControl, usage reporting
Testing Utilities❌ NonecreateTestClient
Production Tooling❌ Minimal✅ Apollo Studio integration

💡 Final Recommendation

Do not use express-graphql in any new project. It’s deprecated, lacks modern GraphQL features, and won’t receive security updates.

Use apollo-server-express if you’re building a production GraphQL API on top of Express. It gives you enterprise-grade tooling, active maintenance, and a clear upgrade path to newer Apollo Server versions (including standalone servers that don’t require Express).

If you’re starting fresh and don’t need Express for other routes, consider using apollo-server (standalone) instead—it removes the Express dependency entirely while keeping the same core API.

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

    Choose apollo-server-express for any new GraphQL API project that needs to integrate with an existing Express application. It is actively maintained, offers rich developer tooling like Apollo Sandbox, supports advanced features such as subscriptions and file uploads, and integrates with production observability platforms like Apollo Studio. It’s the clear choice for professional, maintainable GraphQL services.

  • express-graphql:

    Do not choose express-graphql for new projects. It is officially deprecated, no longer maintained, and lacks modern GraphQL features like subscriptions, persisted queries, and advanced caching. While it may still work for very simple, legacy use cases, it should be avoided in favor of actively supported alternatives like apollo-server-express.

README for apollo-server-express

npm version Build Status Join the community forum Read CHANGELOG

This is the Express integration of Apollo Server. Apollo Server is a community-maintained open-source GraphQL server that works with many Node.js HTTP server frameworks. Read the docs. Read the CHANGELOG.

A full example of how to use apollo-server-express can be found in the docs.

Before Apollo Server 3, we officially supported using this package with connect as well. connect is an older framework that express evolved from. For now, we believe that this package is still compatible with connect and we even run tests against connect, but we may choose to break this compatibility at some point without a major version bump. If you rely on the ability to use Apollo Server with connect, you may wish to make your own integration.

Principles

GraphQL Server is built with the following principles in mind:

  • By the community, for the community: GraphQL Server's development is driven by the needs of developers
  • Simplicity: by keeping things simple, GraphQL Server is easier to use, easier to contribute to, and more secure
  • Performance: GraphQL Server is well-tested and production-ready - no modifications needed

Anyone is welcome to contribute to GraphQL Server, just read CONTRIBUTING.md, take a look at the roadmap and make your first PR!