GraphQL TypeScript - w/ GraphQL-Modules and GraphQL-Code-Generator

Arda Tanrikulu
Looking for experts? We offer consulting and trainings.
Explore our services and get in touch.

Last year we've released GraphQL-Modules (opens in a new tab) — which applies modular approach to large scale, GraphQL-based applications.

We've also released a new version of GraphQL Code Generator (opens in a new tab) which generates server-side typings and signatures for resolvers from GraphQL Schemas.

Those are two separate projects, but because we use both in production across many different applications, we wanted to write about the benefits of the tight integration of those projects and how it provides us with great development experience while implementing our projects in TypeScript.

GraphQL Code Generator can take a JS/TS export from GraphQL-Modules to generate server-side typings (or anything else that its plugins can generate (opens in a new tab)). So, let's export typeDefs without any business logic that includes resolvers, DI, providers etc…

You can create a schema.ts file to expose typeDefs to GraphQL Code Generator:

import { AppModule } from './modules/app'
export default AppModule.typeDefs
// If your module needs a configuration
export default AppModule.forRoot({ ...dummyConfiguration }).typeDefs

Create a codegen.yml config file, including schema.ts as a schema source, and generate common (opens in a new tab) and server (opens in a new tab) typings for TypeScript. We use transpile-only to prevent errors related to TypeScript on typing generation phase to let ts-node handle this on running the actual application.

overwrite: true
schema: ./src/schema.ts
  - ts-node/register/transpile-only
      - typescript
      - typescript-resolvers
      contextType: @graphql-modules/core#ModuleContext

We can add a script to package.json to run:

 "scripts": {
    "generate": "gql-gen",
    // You can use nodemon to watch changes on graphql files
    "generate:watch": "nodemon --exec yarn generate -e graphql",

Then, we can use these typings in our project. This example shows a resolvers handler that implements resolvers for Query type with generated types.

import { UsersProvider } from '../providers/users.provider'
import { IResolvers } from '../../generated-models'
export default <IResolvers>{
  Query: {
    // all parameters and return value are typed
    users: (root, args, context, info) => context.injector.get(UsersProvider).getUsers(args)

At the end, we have a strictly-typed backend project, based of separate feature modules, and each of those modules uses GraphQL and TypeScript.

You can check our working example that is created by using this approach; (opens in a new tab)

All Posts about GraphQL Modules

Join our newsletter

Want to hear from us when there's something new? Sign up and stay up to date!

By subscribing, you agree with Beehiiv’s Terms of Service and Privacy Policy.

Recent issues of our newsletter

Similar articles