107 Running Code Generation for Resolvers and Models
107 Running Code Generation for Resolvers and Models
If you build modern applications with GraphQL and TypeScript—say, using a favorite stack like Apollo Server , NestJS , or GraphQL Yoga —you have surely experienced the repetitive manual work of writing resolvers, models, and mapping GraphQL types to TypeScript. Fortunately, the modern engineering world has provided an “automatic potion” in the form of code generation tools.
In this article, we will walk through, end-to-end, how to run code generation for resolvers and models. You will find code examples, simulations, and even a diagram of the codegen procedure flow using mermaid .
Why Do We Need Code Generation?
Before discussing the “how,” let’s first talk about the “why.” With code generation:
- Productivity increases: There is no need to write resolver and model files manually every time the schema changes.
- Type consistency: No more data type typos or data/response flows that are out of sync.
- Scalability: As the schema grows, codegen saves hundreds of minutes of human effort.
Tool: @graphql-codegen/cli
The most popular tool for code generation in the JavaScript/TypeScript ecosystem is @graphql-codegen/cli
. It is flexible, has many plugins, supports a wide range of frameworks, is easy to integrate into CI/CD, and has an active community.
Diagram: The Code Generation Process
Let’s start from the big picture—here is how the code generation flow for resolvers and models usually proceeds:
flowchart TD
A[Write GraphQL Schema (.graphql)] --> B[Konfigurasi codegen.yml]
B --> C[Run Codegen Command]
C --> D[Generate Typescript Models]
C --> E[Generate Typed Resolvers]
D --> F[Import Model/Types di Project]
E --> F
Setting Up the Simulation Project
For example, let’s use it in a simple TypeScript application.
Directory structure:
1/project-root
2 ├── src/
3 │ ├── resolvers/
4 │ ├── models/
5 │ └── schema.graphql
6 ├── codegen.yml
7 └── package.jsonLet’s start from the schema:
src/schema.graphql:
1type User {
2 id: ID!
3 name: String!
4 email: String!
5}
6
7type Query {
8 users: [User!]!
9 user(id: ID!): User
10}Installing the Codegen Packages
Install the required dependencies:
1npm install --save-dev @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-resolversA brief explanation of the plugins:
typescript: Generates TypeScript types from the GraphQL schema.typescript-resolvers: Generates complete resolver type signatures.
Creating the codegen.yml Configuration
codegen.yml:
1schema: ./src/schema.graphql
2generates:
3 ./src/generated/types.ts:
4 plugins:
5 - typescript
6 - typescript-resolvers
7 config:
8 contextType: ../context#Context
9 maybeValue: T | null // allow null responseKey points:
schema: the path to the GraphQL schema.generates: the target output file.contextType: aligns with the resolver context.plugins: the plugins that will run to generate the code.
Running Code Generation
Command to generate the code:
1npx graphql-codegenAfter running it, you will get a src/generated/types.ts file containing two major things:
- Models generated automatically according to the types in the schema.
- Type signatures for every resolver.
Example of the Generated Output
1. Generated Model Types
Part of the generated types.ts will look like this:
1export type User = {
2 __typename?: 'User';
3 id: string;
4 name: string;
5 email: string;
6};2. Generated Resolver Types
Type-safe resolver signatures are also available:
1export type QueryResolvers<ContextType = Context, ParentType = ResolversParentTypes['Query']> = {
2 users?: Resolver<Array<User>, ParentType, ContextType>,
3 user?: Resolver<Maybe<User>, ParentType, ContextType, RequireFields<QueryUserArgs, 'id'>>,
4};With these definitions, every resolver implementation automatically gets type autocomplete this awesome:
1import { QueryResolvers } from './generated/types';
2
3export const queryResolvers: QueryResolvers = {
4 users: (parent, args, context, info) => {
5 // context: strongly typed!
6 return context.dataSources.userAPI.getAllUsers();
7 },
8 user: (parent, { id }, context) => {
9 return context.dataSources.userAPI.getUserById(id);
10 },
11};Simulating a Schema Change
One of codegen’s selling points: when the schema changes, just regenerate!
For example, add an isActive field:
1type User {
2 id: ID!
3 name: String!
4 email: String!
5 isActive: Boolean!
6}1npx graphql-codegenAll models and resolver signatures are then updated automatically, with no need for a manual sync.
Manual vs. Code Generation Comparison Table
| Category | Manual | With Codegen |
|---|---|---|
| Speed | Slow, lots of boilerplate | Very fast, just generate |
| Human Error | Prone to typos and missing fields | Almost impossible to make typos |
| Type Consistency | Often out of sync with the schema | 100% follows the schema |
| Scalability | Quickly becomes chaos as it grows | Stays manageable at large scale |
| CI/CD Integration | Possible, but easy to miss | Very easy, just run npx |
Best Practices for Implementation
1. Ignore the generated output in VCS
Add /src/generated to .gitignore so the generated output does not flood the repository.
2. Integrate into CI/CD
In the pipeline, run codegen before compilation or testing to ensure all code is up to date.
3. Check for schema breaking changes
A schema change means a mandatory regeneration; lint and build will fail if the types do not match.
4. Custom Plugins
Use other plugins such as typescript-operations if you need to generate code for queries/mutations on the frontend.
Conclusion
By running code generation for resolvers and models, development becomes more scalable, safe from typos, and easy to collaborate on with large teams. Once the codegen pipeline is integrated, your engineers’ productivity will increase many times over.
So, if the “classic enemy” of your GraphQL project is manual boilerplate, it’s time to migrate to code generation. There is no need to worry about how large your schema is, because automation is ready to handle it.
References
Happy coding & automating! 🚀