GraphQL Development Tools and Ecosystem
GraphQL Development Tools and Ecosystem
GraphQL gives you a typed schema, flexible queries, and a single endpoint. But it also gives you a new category of tooling to learn: schema design tools, code generators, client libraries, IDE extensions, and testing utilities. This guide covers the tools that matter most and helps you pick the right ones for your stack.
GraphQL Servers
Apollo Server
Apollo Server is the most widely used GraphQL server for Node.js/TypeScript. It's mature, well-documented, and integrates with Express, Fastify, and serverless platforms.
import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
const typeDefs = `
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
author: User!
}
type Query {
users: [User!]!
user(id: ID!): User
}
type Mutation {
createUser(name: String!, email: String!): User!
}
`;
const resolvers = {
Query: {
users: (_, __, { dataSources }) => dataSources.usersAPI.getAll(),
user: (_, { id }, { dataSources }) => dataSources.usersAPI.getById(id),
},
User: {
posts: (user, _, { dataSources }) => dataSources.postsAPI.getByAuthor(user.id),
},
};
const server = new ApolloServer({ typeDefs, resolvers });
const { url } = await startStandaloneServer(server, { listen: { port: 4000 } });
Strengths: Huge ecosystem, excellent documentation, plugin system for caching/tracing/auth, Apollo Federation for microservices.
Weaknesses: Can feel heavy for simple APIs. Apollo's commercial features (Studio, Router) sometimes blur the line between open source and paid.
GraphQL Yoga
GraphQL Yoga (by The Guild) is a lighter alternative built on standard web APIs (Request/Response). It works everywhere -- Node.js, Bun, Deno, Cloudflare Workers, and serverless.
import { createSchema, createYoga } from "graphql-yoga";
const yoga = createYoga({
schema: createSchema({
typeDefs: `
type Query {
hello(name: String): String!
}
`,
resolvers: {
Query: {
hello: (_, { name }) => `Hello ${name || "World"}`,
},
},
}),
});
// Works with any framework
Bun.serve({ fetch: yoga.fetch, port: 4000 });
Strengths: Lightweight, built on web standards (runs anywhere), Envelop plugin system, SSE subscriptions (no WebSocket server needed), excellent TypeScript support.
Weaknesses: Smaller community than Apollo, fewer enterprise features.
Recommendation: Use Yoga for new projects and edge deployments. Use Apollo Server if you need Federation or are already invested in the Apollo ecosystem.
Client Libraries
urql
urql is a lightweight, extensible GraphQL client for React (and other frameworks). It's simpler than Apollo Client while covering most use cases.
import { createClient, cacheExchange, fetchExchange } from "urql";
const client = createClient({
url: "https://api.example.com/graphql",
exchanges: [cacheExchange, fetchExchange],
});
import { useQuery } from "urql";
const UsersQuery = `
query {
users {
id
name
email
}
}
`;
function UserList() {
const [result] = useQuery({ query: UsersQuery });
const { data, fetching, error } = result;
if (fetching) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{data.users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Strengths: Small bundle size (~5kb gzipped), document caching by default, extensible via exchanges, works with React, Vue, Svelte.
Apollo Client
Apollo Client is the most feature-rich GraphQL client. Its normalized cache is powerful but complex.
import { ApolloClient, InMemoryCache, gql } from "@apollo/client";
const client = new ApolloClient({
uri: "https://api.example.com/graphql",
cache: new InMemoryCache(),
});
// The normalized cache automatically deduplicates entities
// If you fetch a user in two different queries, they share the same cache entry
Strengths: Normalized cache (automatic deduplication), mature devtools extension, local state management, optimistic updates.
Weaknesses: Large bundle (~30kb gzipped), steep learning curve for cache configuration, cache normalization bugs can be subtle and hard to debug.
Recommendation: Start with urql. Move to Apollo Client if you need normalized caching or are building a complex app where cache deduplication matters.
Code Generation
Code generation is the most impactful tool in the GraphQL ecosystem. It takes your schema and queries and generates typed code -- eliminating an entire category of bugs.
GraphQL Code Generator
GraphQL Codegen (by The Guild) generates TypeScript types, typed React hooks, and more from your schema and operations.
npm install -D @graphql-codegen/cli @graphql-codegen/typescript \
@graphql-codegen/typescript-operations @graphql-codegen/typed-document-node
# codegen.ts
import type { CodegenConfig } from "@graphql-codegen/cli";
const config: CodegenConfig = {
schema: "https://api.example.com/graphql",
documents: "src/**/*.graphql",
generates: {
"src/generated/graphql.ts": {
plugins: [
"typescript",
"typescript-operations",
"typed-document-node",
],
},
},
};
export default config;
npx graphql-codegen
Now your queries are fully typed:
import { UsersDocument } from "./generated/graphql";
// UsersDocument is a TypedDocumentNode -- the client knows the exact return type
const result = await client.query(UsersDocument);
result.data.users[0].name; // fully typed, autocomplete works
result.data.users[0].foo; // TypeScript error: 'foo' does not exist
gql.tada
gql.tada is a newer approach that uses TypeScript's type system to infer types at compile time -- no code generation step needed.
import { graphql } from "gql.tada";
const UsersQuery = graphql(`
query Users {
users {
id
name
email
}
}
`);
// Types are inferred from the query string at compile time
// No codegen step, no generated files
Strengths: No build step, instant type updates when you change a query, works with any editor that supports TypeScript.
Weaknesses: Requires TypeScript 4.1+ template literal types, can slow down the TypeScript compiler on large schemas, the setup involves loading your schema into the type system.
Recommendation: Use GraphQL Codegen for most projects -- it's mature and well-supported. Try gql.tada if you hate code generation steps and have a moderate-sized schema.
IDE Tooling
GraphQL Language Server
The GraphQL foundation maintains a language server that powers editor extensions across VS Code, JetBrains, Vim, and Emacs.
VS Code: GraphQL Language Features (official extension):
- Syntax highlighting for
.graphqlfiles and tagged template literals - Autocomplete for fields, arguments, and types
- Inline validation against your schema
- Go-to-definition for types and fields
- Hover documentation
Configure it with a .graphqlrc.yml:
# .graphqlrc.yml
schema: "https://api.example.com/graphql"
documents: "src/**/*.{ts,tsx,graphql}"
Apollo GraphQL Extension
If you're using Apollo, their VS Code extension adds Apollo-specific features: integration with Apollo Studio, schema registry support, and field usage analytics.
API Exploration and Testing
GraphiQL
GraphiQL is the standard in-browser GraphQL IDE. Most GraphQL servers include it by default. It provides:
- Interactive query building with autocomplete
- Schema documentation browser
- Query history
- Variable editor
If your server doesn't include it, you can add it:
// With Yoga, it's built in -- visit http://localhost:4000/graphql
// With Apollo Server, enable the Explorer plugin or use Apollo Sandbox
Postman and Insomnia
Both Postman and Insomnia support GraphQL with schema introspection, autocomplete, and variable management. They're useful when you want to save GraphQL queries alongside REST requests in the same collection.
Testing with MSW
Mock Service Worker works excellently for testing GraphQL clients:
import { graphql, HttpResponse } from "msw";
export const handlers = [
graphql.query("Users", () => {
return HttpResponse.json({
data: {
users: [
{ id: "1", name: "Alice", email: "[email protected]" },
{ id: "2", name: "Bob", email: "[email protected]" },
],
},
});
}),
graphql.mutation("CreateUser", ({ variables }) => {
return HttpResponse.json({
data: {
createUser: {
id: "3",
name: variables.name,
email: variables.email,
},
},
});
}),
];
Schema Design Tools
GraphQL Voyager
Voyager generates an interactive visualization of your GraphQL schema as a graph. Types are nodes, relationships are edges. It's the fastest way to understand a complex schema.
# Use it online at https://graphql-kit.com/graphql-voyager/
# Or embed it in your app
npm install graphql-voyager
GraphQL Inspector
GraphQL Inspector detects breaking changes between schema versions and validates your schema against best practices.
npx graphql-inspector diff old-schema.graphql new-schema.graphql
Output:
- Field 'User.email' was removed (BREAKING)
- Field 'User.emailAddress' was added
- Input field 'CreateUserInput.name' changed type from 'String' to 'String!' (BREAKING)
This belongs in your CI pipeline. Catch breaking schema changes before they reach production.
Recommendations
- Server: Use GraphQL Yoga for new projects. It's lightweight, runs everywhere, and has an excellent plugin system. Use Apollo Server if you need Federation.
- Client: Start with urql for simplicity. Move to Apollo Client only if you need normalized caching.
- Code generation: Use GraphQL Codegen. The typed document nodes plugin eliminates type errors between queries and code. Run it in watch mode during development.
- IDE: Install the GraphQL Language Features extension for VS Code. Configure
.graphqlrc.ymlto point at your schema. The autocomplete and validation alone are worth it. - Testing: Use MSW for client-side testing. Use GraphQL Inspector in CI to catch breaking schema changes.
- General principle: GraphQL's type system is its biggest advantage. Use code generation and IDE tooling to exploit it fully. If you're writing GraphQL without generated types, you're losing half the value.