GraphQL Tooling: A Codegen Overview
An overview of GraphQL code generation: what it does, how schemas and operations turn into typed clients, and how to wire it into a modern frontend workflow.
What you'll learn
- ✓What GraphQL codegen produces and why
- ✓How schema and operation files combine
- ✓Common plugin choices and their trade-offs
- ✓Wiring codegen into a dev loop
- ✓Patterns for keeping generated code healthy
Prerequisites
- •Familiar with HTTP and databases
What and Why
GraphQL codegen reads your schema and your client operations, then writes type definitions, hooks, and helpers that match exactly. Instead of hand-writing TypeScript interfaces for every query response, you let the tool do it. The benefit compounds: every schema change either updates types automatically or fails the build, so drift between server and client becomes visible immediately.
Without codegen, teams typically inline any types or maintain parallel hand-written interfaces. Both options decay as the schema evolves. Codegen makes the schema the single source of truth.
Mental Model
Think of codegen as a compiler with two inputs and one output:
- Input A: the schema (SDL or introspection JSON) defines all available types and fields.
- Input B: your operations (
.graphqlfiles or inlinegqltags) define what you actually use. - Output: typed artifacts tailored to each operation, exposing only fields you selected.
The key insight is that operations are narrower than the schema. If you query { user { id name } }, the generated type contains exactly id and name, nothing else. This precision is what makes generated types more useful than the schema’s raw object types.
Hands-on Example
A typical config (codegen.yml) might look like:
schema: https://api.example.com/graphql
documents: 'src/**/*.graphql'
generates:
src/gql/types.ts:
plugins:
- typescript
- typescript-operations
src/gql/hooks.ts:
plugins:
- typescript
- typescript-operations
- typescript-react-apollo
Given a GetUser.graphql:
query GetUser($id: ID!) {
user(id: $id) { id name email }
}
Codegen emits a useGetUserQuery hook with a fully typed result. The component code becomes:
const { data, loading } = useGetUserQuery({ variables: { id } });
if (data?.user) console.log(data.user.email);
schema.graphql operations/*.graphql
\ /
\ /
v v
+-----------------------+
| codegen runner |
| (plugins + config) |
+-----------+-----------+
|
+----------+----------+
v v v
types.ts hooks.ts fragments
\ | /
\ v /
import in app code
Common Pitfalls
- Committing generated files but forgetting to regenerate. CI should run codegen and fail if the diff is non-empty.
- Pointing at a stale schema snapshot. Either fetch from a known environment or version the schema file alongside server code.
- Generating against production while developing local schema changes. Use a local schema file in development to keep loops fast and predictable.
- Letting fragment names collide. Codegen requires unique operation and fragment names across the project; pick a naming convention early.
- Overusing scalar types without configuration. Custom scalars like
DateTimedefault toany; map them explicitly toDateorstringin config. - Mixing multiple GraphQL clients in one repo. Codegen plugins are client-specific; standardizing on one client first avoids two generated worlds.
Practical Tips
Run codegen in watch mode during development. Most setups regenerate within milliseconds of saving a .graphql file, making the type feedback feel instant.
Adopt the client-preset (or your client’s equivalent). It generates a typed graphql() function so inline operations are typed without separate hook generation, reducing boilerplate.
Lint operations as part of the codegen step. Plugins can flag deprecated fields, missing fragments, or selection sets that violate your style guide before code review.
Treat generated files as build artifacts. Either gitignore them and regenerate in CI, or commit them and enforce regeneration. Inconsistent approaches confuse contributors.
Scope your operations carefully. Co-locate .graphql files with the components that use them so codegen output mirrors your component tree, making refactors safer.
Version the schema in the server repo and publish it for clients. A schema registry (or a simple npm package) lets clients pin versions and migrate deliberately.
Wrap-up
GraphQL codegen turns a schema into a strict contract between server and client. With a small config and a watch process, you trade hand-written types for compiler-enforced safety. Pick a plugin set that matches your client, automate regeneration, and let your editor catch schema drift before your users do.
Related articles
- GraphQL GraphQL Caching with Apollo Client
How Apollo Client's normalized cache works, why entity IDs matter, and the patterns for cache updates, refetches, and consistent UI after mutations.
- GraphQL GraphQL Error Handling Best Practices
Compare the errors array, union result types, and partial responses to design predictable, typed error handling for your GraphQL APIs and clients.
- GraphQL GraphQL Federation: A Practical Overview
Understand Apollo Federation: subgraphs, the gateway, entity references, and when to choose federation over a monolithic GraphQL schema.
- GraphQL GraphQL N+1 and DataLoader
Why GraphQL resolvers cause N+1 query storms and how DataLoader batches and caches them away. Clear examples, real code, and the pitfalls.