On large projects, a frontend without a single source of truth for data types quickly turns into a nightmare. Especially when the product isn’t in production yet and the backend and analytics evolve faster than button colors.
One architectural decision significantly simplified the team’s workflow and reduced errors and manual debugging: type generation using graphql-codegen combined with a strict backend deployment workflow.
How it worked
- Backend updates GraphQL schemas for microservices.
- Frontend pulls the latest schemas, created query/mutation and regenerates types.
- Any breaking changes are caught before the frontend build.
This approach allowed us to detect all mismatches between backend queries and responses at frontend build time, long before they reached runtime.
How it created
To integrate type generation, you need to add the following dependencies to your project:
- graphql-codegen/cli
- graphql-codegen/typescript
- graphql-codegen/typescript-document-nodes
- graphql-codegen/typescript-operations
Type generation and updates are configured via a YAML file for GraphQL Code Generator.
A typical setup for generating types from a local schema looks like this:
# Should existing files be overwritten after generation
overwrite: true
generates:
# Path to the generated output
src/generated/schema.graphql.ts:
# Path to the GraphQL schema
schema: ./graphql-schema/schema.graphql
# GraphQL documents (queries/mutations) to parse in the project
documents: src/**/*.graphql
plugins:
- typescript
- typescript-operations
- typescript-document-nodes
For generating types based on introspection queries, the setup is very similar. You just need to provide the URL of the GraphQL endpoint:
overwrite: true
generates:
src/generated/introspection.graphql.ts:
# GraphQL endpoint URL
schema: "http://localhost:4000/graphql"
documents: "src/**/*.graphql"
plugins:
- typescript
- typescript-operations
- typescript-document-nodes
Running the Generation
For convenience, you can define scripts in package.json:
"scripts": {
"codegen:schema": "npx graphql-codegen --config codegen-schema.yml",
"codegen:introspection": "npx graphql-codegen --config codegen-introspection.yml"
}
When writing queries or mutations in code, it’s convenient to define the request body as a variable and type it using the generated types. For example:
# GraphQL Query
query GetOpportunities($request: GetOpportunitiesRequestInput!) {
opportunities(request: $request) {
statusCode
message
data {
contractNumber
creationDate
}
}
}
// Type-safe variables
const variables: GetOpportunitiesThemesQueryVariables = {
providerId: test1,
keycloakUserId: test2,
};
// Query using your Apollo service (example from my project)
this.apollo
.watchQueryWithService<GetOpportunitiesThemesQuery>(
'accreditationService',
{
query: GetOpportunitiesThemes,
variables,
}
);
Conclusion
Using GraphQL Codegen and a strict backend deployment workflow allows frontend teams to stay in sync with backend changes, catch mismatches at build time, and significantly reduce manual debugging.
This approach is applicable for both GraphQL SDL and introspection-based workflows, and it scales well for projects with multiple microservices.
Happy to hear your thoughts or discuss alternative approaches — feel free to try the setup in your own project!
Github
I’ve prepared a repository where you can spin up a backend and experiment with automatic type generation using GraphQL introspection and GraphQL SDL:
👉 https://github.com/IAGrekhovFronted/Type-Safe-Angular-Graphql
You can also check a similar approach for client and type generation over REST.
The stack is different (.NET + Next.js), but the core idea is very similar:
👉 https://github.com/IAGrekhovFronted/Healt-Nutrition-Test-Project
Hope this approach or the examples will be useful — happy to hear your thoughts or discuss alternatives.
Top comments (0)