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.
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.
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-graphqlshould be ruled out immediately due to deprecation.
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();
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 });
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;
}
});
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:
graphql-upload integration)cacheControlExample: 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.
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.
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.
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.
| Feature | express-graphql | apollo-server-express |
|---|---|---|
| Maintenance Status | ❌ Deprecated | ✅ Actively maintained |
| Built-in IDE | GraphiQL (basic) | Apollo Sandbox (modern) |
| Subscriptions | ❌ Not supported | ✅ Supported |
| File Uploads | ❌ Manual implementation | ✅ Built-in |
| Caching / Tracing | ❌ None | ✅ CacheControl, usage reporting |
| Testing Utilities | ❌ None | ✅ createTestClient |
| Production Tooling | ❌ Minimal | ✅ Apollo Studio integration |
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.
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.
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.
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.
GraphQL Server is built with the following principles in mind:
Anyone is welcome to contribute to GraphQL Server, just read CONTRIBUTING.md, take a look at the roadmap and make your first PR!