apollo-server vs graphql-compose vs graphql-modules vs graphql-tools vs nexus vs type-graphql
Architecting GraphQL Servers in Node.js
apollo-servergraphql-composegraphql-modulesgraphql-toolsnexustype-graphqlSimilar Packages:

Architecting GraphQL Servers in Node.js

These libraries provide the core building blocks for creating GraphQL APIs in Node.js environments. apollo-server offers a complete server implementation, while graphql-tools focuses on schema utilities and stitching. nexus and type-graphql enable code-first schema definition using TypeScript, and graphql-compose allows dynamic schema generation. graphql-modules aims to organize large schemas into manageable pieces. Together, they cover the spectrum from schema design to server execution.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
apollo-server013,95226.6 kB883 years agoMIT
graphql-compose01,210921 kB8419 days agoMIT
graphql-modules01,327220 kB544 months agoMIT
graphql-tools05,4292.64 kB1257 days agoMIT
nexus03,4302.17 MB254-MIT
type-graphql08,086351 kB1208 months agoMIT

Architecting GraphQL Servers in Node.js: Schema, Code, and Execution

Building a GraphQL API involves three main layers: defining the schema, writing resolvers, and running the server. The packages apollo-server, graphql-compose, graphql-modules, graphql-tools, nexus, and type-graphql each tackle these layers differently. Some focus on schema definition, others on server execution, and some on organizing large codebases. Let's break down how they handle the core tasks of API development.

πŸ“ Defining Types: SDL vs Code-First

How you define your GraphQL types sets the tone for your entire project. Some tools use GraphQL SDL (Schema Definition Language), while others generate the schema from TypeScript code.

apollo-server traditionally uses SDL strings or the gql tag to define types manually.

// apollo-server: SDL Definition
const typeDefs = gql`
  type User {
    id: ID!
    name: String!
  }
`;

graphql-compose builds types dynamically using JavaScript objects.

// graphql-compose: Dynamic Composition
const UserTC = composer.createObjectTC({
  name: 'User',
  fields: {
    id: 'ID!',
    name: 'String!',
  },
});

graphql-modules uses SDL files split across modules.

// graphql-modules: Module SDL
// user-module/types.graphql
type User {
  id: ID!
  name: String!
}

graphql-tools relies on SDL strings to make schemas executable.

// graphql-tools: SDL String
const typeDefs = `
  type User {
    id: ID!
    name: String!
  }
`;

nexus defines types using TypeScript functions and chaining.

// nexus: Code-First TypeScript
const User = objectType({
  name: 'User',
  definition(t) {
    t.id('id');
    t.string('name');
  },
});

type-graphql uses TypeScript classes with decorators.

// type-graphql: Decorator Class
@ObjectType()
class User {
  @Field(() => ID)
  id: string;
  @Field()
  name: string;
}

βš™οΈ Writing Resolvers: Functions vs Classes

Resolvers contain the logic for fetching data. The structure varies from simple maps to class methods.

apollo-server uses a simple map of functions matching type fields.

// apollo-server: Resolver Map
const resolvers = {
  User: {
    name: (parent) => parent.fullName,
  },
};

graphql-compose attaches resolvers directly to type composers.

// graphql-compose: Resolver Attachment
UserTC.addResolver({
  name: 'getUser',
  resolve: async ({ args }) => {
    return db.find(args.id);
  },
});

graphql-modules defines resolvers within module files.

// graphql-modules: Module Resolvers
// user-module/resolvers.js
export default {
  User: {
    name: (parent) => parent.fullName,
  },
};

graphql-tools pairs SDL with a separate resolver map.

// graphql-tools: Resolver Map
const resolvers = {
  Query: {
    user: () => ({ id: '1', name: 'Alice' }),
  },
};

nexus defines resolvers inside the type definition block.

// nexus: Inline Resolvers
const User = objectType({
  name: 'User',
  definition(t) {
    t.string('name', {
      resolve: (parent) => parent.fullName,
    });
  },
});

type-graphql places resolvers as methods inside the class.

// type-graphql: Class Methods
@ObjectType()
class User {
  @Field()
  name: string;

  @ResolveField()
  async getName(@Parent() parent) {
    return parent.fullName;
  }
}

πŸš€ Starting the Server: Built-In vs Bring-Your-Own

Some packages include a HTTP server, while others require you to connect them to Express, Fastify, or similar.

apollo-server includes a standalone server that starts listening immediately.

// apollo-server: Standalone Start
const server = new ApolloServer({ typeDefs, resolvers });
await server.start();
server.listen(4000);

graphql-compose does not start a server; it exports a schema for you to use.

// graphql-compose: Schema Export
const schema = composer.buildSchema();
// Pass 'schema' to any server like express-graphql or apollo-server

graphql-modules produces a schema module to be consumed by a server.

// graphql-modules: Module Assembly
const { schema } = createSchema({ modules });
// Pass 'schema' to your preferred server implementation

graphql-tools creates an executable schema but requires a separate server.

// graphql-tools: Make Executable
const schema = makeExecutableSchema({ typeDefs, resolvers });
// Pass 'schema' to a server like @apollo/server

nexus generates a schema that needs a server runtime.

// nexus: Schema Generation
const schema = makeSchema({ types: [User] });
// Pass 'schema' to @apollo/server or similar

type-graphql builds a schema from classes that needs a server.

// type-graphql: Build Schema
const schema = await buildSchema({
  resolvers: [UserResolver],
});
// Pass 'schema' to @apollo/server or similar

🧩 Modularity: Splitting Large Codebases

As APIs grow, keeping code organized becomes critical. Some tools enforce structure, while others leave it to you.

apollo-server has no built-in modularity; you must organize files manually.

// apollo-server: Manual Organization
// You must merge typeDefs and resolvers yourself
const typeDefs = [...userTypes, ...postTypes];

graphql-compose encourages composition but lacks strict module boundaries.

// graphql-compose: Composer Grouping
const UserTC = composer.createObjectTC({ name: 'User' });
const PostTC = composer.createObjectTC({ name: 'Post' });
// Developer manages relationships manually

graphql-modules enforces strict module boundaries with dependency injection.

// graphql-modules: Explicit Dependencies
createSchema({
  modules: [
    { name: 'user', path: './user' },
    { name: 'post', path: './post', dependencies: ['user'] },
  ],
});

graphql-tools supports schema stitching to merge multiple schemas.

// graphql-tools: Stitching
const gatewaySchema = stitchSchemas({
  subschemas: [serviceASchema, serviceBSchema],
});

nexus uses plugins and folder structures for organization.

// nexus: Plugin Organization
makeSchema({
  types: [User, Post],
  plugins: [fieldTypePlugin()],
});

type-graphql relies on TypeScript project structure and container scanning.

// type-graphql: Resolver Scanning
buildSchema({
  resolvers: [__dirname + '/resolvers/**/*.ts'],
});

⚠️ Maintenance and Future Proofing

Choosing a library means committing to its long-term support. Some packages are shifting focus or entering maintenance mode.

apollo-server standalone package is in maintenance mode. Migration to @apollo/server is recommended for new projects.

// apollo-server: Deprecation Notice
// npm install apollo-server (Legacy)
// npm install @apollo/server (Current Standard)

graphql-compose remains stable but has a smaller community than code-first options.

// graphql-compose: Stability
// Active maintenance but niche use cases

graphql-modules development has slowed; consider alternatives for new greenfield projects.

// graphql-modules: Activity Warning
// Check GitHub issues for recent activity before adopting

graphql-tools is actively maintained by The Guild and widely used for stitching.

// graphql-tools: Active Maintenance
// Regular updates for schema stitching and mocks

nexus is actively developed with strong TypeScript focus.

// nexus: Active Development
// Frequent updates for TypeScript compatibility

type-graphql is actively maintained with regular feature releases.

// type-graphql: Active Maintenance
// Regular updates for decorator support and TypeScript

🀝 Similarities: Shared Ground Between Libraries

Despite their differences, these tools share common goals and underlying technologies.

1. πŸ“œ All Rely on GraphQL Spec

  • Every package produces a standard GraphQL schema.
  • Compatible with any GraphQL client (Apollo Client, Relay, etc.).
// Shared Output: Standard GraphQL Schema
// All packages ultimately produce this structure
type Query {
  user(id: ID!): User
}

2. πŸ”Œ TypeScript Support

  • All packages offer TypeScript types or definitions.
  • nexus and type-graphql provide the strongest inference.
// Shared Goal: Type Safety
// All aim to prevent runtime errors via static types
interface User {
  id: string;
}

3. πŸ§ͺ Testing Capabilities

  • All support unit testing resolvers and schema validation.
  • graphql-tools provides specific mocking utilities.
// Shared Practice: Mocking
// All allow mocking data for tests
const mocks = { User: () => ({ name: 'Mocked' }) };

4. 🌐 Ecosystem Integration

  • All work with Express, Fastify, and AWS Lambda.
  • Compatible with Apollo Federation (with configuration).
// Shared Integration: Express
app.use('/graphql', graphqlHTTP({ schema }));

πŸ“Š Summary: Key Differences

Featureapollo-servergraphql-composegraphql-modules
Primary RoleπŸš€ Server Execution🧩 Dynamic SchemaπŸ“¦ Modular Organization
Schema StyleπŸ“œ SDLπŸ› οΈ JS ObjectsπŸ“œ SDL Modules
Server Includedβœ… Yes❌ No❌ No
Status⚠️ Maintenance Modeβœ… Stable⚠️ Slowed Development
Featuregraphql-toolsnexustype-graphql
Primary RoleπŸ› οΈ Utilities/StitchingπŸ’» Code-First Schema🎨 Decorator Schema
Schema StyleπŸ“œ SDLπŸ’» TypeScript Functions🎨 TypeScript Classes
Server Included❌ No❌ No❌ No
Statusβœ… Activeβœ… Activeβœ… Active

πŸ’‘ The Big Picture

apollo-server is the classic choice for running a server β€” but migrate to @apollo/server for new work. It handles the HTTP layer so you don't have to.

graphql-tools is the utility belt. Use it when you need to stitch schemas or mock data, not for running the server itself.

nexus and type-graphql are the modern TypeScript choices. Pick nexus for clean functional code, or type-graphql if you love decorators and classes.

graphql-compose fits dynamic needs where schemas change based on data models.

graphql-modules helps organize massive codebases but requires checking current activity levels.

Final Thought: For most new TypeScript projects, pairing nexus or type-graphql with @apollo/server offers the best balance of type safety and maintenance. Use graphql-tools when you need to connect multiple services together.

How to Choose: apollo-server vs graphql-compose vs graphql-modules vs graphql-tools vs nexus vs type-graphql

  • apollo-server:

    Choose apollo-server if you need a ready-to-run server with built-in features like caching and tracing. Note that the standalone package is in maintenance mode, so evaluate @apollo/server for new projects. It works well for teams wanting a standard, batteries-included setup without custom server configuration.

  • graphql-compose:

    Choose graphql-compose if you need to generate schemas dynamically based on database models or CMS structures. It shines when your schema must adapt to changing data structures without manual updates. This is ideal for admin panels or platforms where users define their own data fields.

  • graphql-modules:

    Choose graphql-modules if you are managing a very large schema that needs strict modularization. It helps split logic into feature-based modules with clear boundaries. Use this for enterprise monoliths where team separation and schema organization are critical pain points.

  • graphql-tools:

    Choose graphql-tools if you need utilities for schema stitching, mocking, or wrapping existing schemas. It is not a server itself but pairs with any GraphQL server implementation. This is the go-to choice for gateway architectures or when integrating multiple downstream GraphQL services.

  • nexus:

    Choose nexus if you prefer a code-first approach with strong TypeScript inference and no decorators. It provides excellent autocompletion and type safety without requiring a compilation step for decorators. Ideal for TypeScript-heavy teams who want clean, standard syntax.

  • type-graphql:

    Choose type-graphql if you come from an Angular or NestJS background and prefer decorator-based metadata. It closely mirrors TypeORM patterns, making it familiar for developers using entity-based architectures. Best for teams that want class-based schema definition with minimal boilerplate.

README for apollo-server

Apollo Server

A TypeScript GraphQL Server for Express, Koa, Hapi, Lambda, and more.

npm version Build Status Join the community forum Read CHANGELOG

Apollo Server is a community-maintained open-source GraphQL server. It works with many Node.js HTTP server frameworks, or can run on its own with a built-in Express server. Apollo Server works with any GraphQL schema built with GraphQL.js--or define a schema's type definitions using schema definition language (SDL).

Read the documentation for information on getting started and many other use cases and follow the CHANGELOG for updates.

Principles

Apollo Server is built with the following principles in mind:

  • By the community, for the community: Its development is driven by the needs of developers.
  • Simplicity: By keeping things simple, it is more secure and easier to implement and contribute.
  • Performance: It is well-tested and production-ready.

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

Getting started

To get started with Apollo Server:

  • Install with npm install apollo-server-<integration> graphql
  • Write a GraphQL schema
  • Use one of the following snippets

There are two ways to install Apollo Server:

  • Standalone: For applications that do not require an existing web framework, use the apollo-server package.
  • Integrations: For applications with a web framework (e.g. express, koa, hapi, etc.), use the appropriate Apollo Server integration package.

For more info, please refer to the Apollo Server docs.

Installation: Standalone

In a new project, install the apollo-server and graphql dependencies using:

npm install apollo-server graphql

Then, create an index.js which defines the schema and its functionality (i.e. resolvers):

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

// The GraphQL schema
const typeDefs = gql`
  type Query {
    "A simple type for getting started!"
    hello: String
  }
`;

// A map of functions which return data for the schema.
const resolvers = {
  Query: {
    hello: () => 'world',
  },
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

server.listen().then(({ url }) => {
  console.log(`πŸš€ Server ready at ${url}`);
});

Due to its human-readability, we recommend using schema-definition language (SDL) to define a GraphQL schema--a GraphQLSchema object from graphql-js can also be specified instead of typeDefs and resolvers using the schema property:

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

Finally, start the server using node index.js and go to the URL returned on the console.

For more details, check out the Apollo Server Getting Started guide and the fullstack tutorial.

For questions, the Apollo community forum is a great place to get help.

Installation: Integrations

While the standalone installation above can be used without making a decision about which web framework to use, the Apollo Server integration packages are paired with specific web frameworks (e.g. Express, Koa, hapi).

The following web frameworks have Apollo Server integrations, and each of these linked integrations has its own installation instructions and examples on its package README.md:

Context

A request context is available for each request. When context is defined as a function, it will be called on each request and will receive an object containing a req property, which represents the request itself.

By returning an object from the context function, it will be available as the third positional parameter of the resolvers:

new ApolloServer({
  typeDefs,
  resolvers: {
    Query: {
      books: (parent, args, context, info) => {
        console.log(context.myProperty); // Will be `true`!
        return books;
      },
    }
  },
  context: async ({ req }) => {
    return {
      myProperty: true
    };
  },
})

Documentation

The Apollo Server documentation contains additional details on how to get started with GraphQL and Apollo Server.

The raw Markdown source of the documentation is available within the docs/ directory of this monorepo--to contribute, please use the Edit on GitHub buttons at the bottom of each page.

Development

If you wish to develop or contribute to Apollo Server, we suggest the following:

  • Fork this repository

  • Install Direnv (a tool that automatically sets up environment variables in project directories) or nvm. We use nvm to ensure we're running the expected version of Node (and we use Direnv to install and run nvm automatically).

  • Install the Apollo Server project on your computer

git clone https://github.com/[your-user]/apollo-server
cd apollo-server
direnv allow  # sets up nvm for you; if you installed nvm yourself, try `nvm install` instead
  • Build and test
npm install
npm test
  • To run individual test files, run npm run pretest && npx jest packages/apollo-server-foo/src/__tests__/bar.test.ts. Note that you do need to re-compile TypeScript before each time you run a test, or changes across packages may not be picked up. Instead of running npm run pretest from scratch before each test run, you can also run tsc --build tsconfig.json --watch in another shell, or use the VSCode Run Build Task to run that for you.

Community

Are you stuck? Want to contribute? Come visit us in the Apollo community forum!

Maintainers

Who is Apollo?

Apollo builds open-source software and a graph platform to unify GraphQL across your apps and services. We help you ship faster with:

  • Apollo Studio – A free, end-to-end platform for managing your GraphQL lifecycle. Track your GraphQL schemas in a hosted registry to create a source of truth for everything in your graph. Studio provides an IDE (Apollo Explorer) so you can explore data, collaborate on queries, observe usage, and safely make schema changes.
  • Apollo Federation – The industry-standard open architecture for building a distributed graph. Use Apollo’s gateway to compose a unified graph from multiple subgraphs, determine a query plan, and route requests across your services.
  • Apollo Client – The most popular GraphQL client for the web. Apollo also builds and maintains Apollo iOS and Apollo Android.
  • Apollo Server – A production-ready JavaScript GraphQL server that connects to any microservice, API, or database. Compatible with all popular JavaScript frameworks and deployable in serverless environments.

Learn how to build with Apollo

Check out the Odyssey learning platform, the perfect place to start your GraphQL journey with videos and interactive code challenges. Join the Apollo Community to interact with and get technical help from the GraphQL community.