Setting up GraphQL Code Generator with Gatsby

For my Gatsby site, I automatically generate GraphQL query types for TypeScript, with GraphQL Code Generator. This tool reads your Gatsby GraphQL schema, parses Gatsby's code for graphql tags, then creates TypeScript type definitions for all the GraphQL queries.

Here's how you can set-up GraphQL Code Generator in your own Gatsby site.

Installing Dependencies

First, install GraphQL Code Generator CLI and plugin dependencies from npm:

shell
yarn add -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations

Configuring the Code Generator

Get your site running locally with yarn develop. Here's my terminal output after Gatsby works its site generation magic:

terminal
You can now view rohan-chandra-personal-website in the browser.
http://localhost:8000/
View GraphiQL, an in-browser IDE, to explore your site's data and schema
http://localhost:8000/___graphql
Note that the development build is not optimized.
To create a production build, use gatsby build

The ever-helpful Gatsby points us to http://localhost:8000/___graphql. This site allows you to explore your GraphQL data and schema. Here's the important part: GraphQL Code Generator can access this same URL to access the GraphQL schema!

Next to your package.json, create a codegen.yaml, with the link to the schema:

./codegen.yamlyaml
overwrite: true
schema: http://localhost:8000/___graphql
documents:
- ./src/**/*.{ts,tsx}
generates:
./src/graphqlTypes.ts:
plugins:
- typescript
- typescript-operations
config:
avoidOptionals: true
maybeValue: "T"
namingConvention:
enumValues: "keep"
# Uncomment to reformat types with prettier.
# hooks:
# afterOneFileWrite:
# - prettier --write

Running the Code Generator

With our code generation config now set up, head to the scripts section of package.json. Add in:

./package.jsonjson
"scripts": {
"codegen": "graphql-codegen --config codegen.yaml",
"codegen:watch": "graphql-codegen --config codegen.yaml --watch"
}

Here's the fun part. Make sure your Gatsby site is running locally with yarn develop, then (in another terminal) run graphql-codegen:

shell
yarn codegen

In ./src/graphqlTypes.ts, you'll see your generated types. Here's what the first couple of lines look like:

typescript
export type Maybe<T> = T;
export type Exact<T extends { [key: string]: unknown }> = {
[K in keyof T]: T[K];
};

I know what you're thinking: yarn codegen every time I write a new GraphQL query? 😢 Thankfully, with the --watch flag (in the second script added in package.json above), we can regenerate types whenever the code changes:

shell
yarn codegen:watch

Examples

The code generator parses the graphql tag and uses the query name as the type name.

Let's walk-through two examples to see this in action. You'll want yarn develop and yarn codegen:watch running in two terminals, if you'd like to follow along.

Static Query Hook Example

Here's an example of using the static query hook from Gatsby. I have my Gatsby site running (with yarn develop, which makes the GraphQL schema accessible) and the code generator keeping an eye on any new code (with yarn codegen:watch).

Create a file of ./src/pages/codegen.tsx with the below code. Visit http://localhost:8000/codegen to checkout your new page!

./src/pages/codegen.tsxtsx
import React from "react";
import { graphql, useStaticQuery } from "gatsby";
import { DemoQuery } from "-/graphqlTypes";
const CodegenPage: React.FC = () => {
const data = useStaticQuery<DemoQuery>(graphql`
query Demo {
site {
siteMetadata {
title
}
}
}
`);
return (
<>
<p>{data.site.siteMetadata.title}</p>
</>
);
};
export default CodegenPage;

Pay special attention to the query name: the generated type is DemoQuery, as I named the query as Demo. The generated types are in the ./src/graphqlTypes.ts file, which is imported with:

tsx
import { DemoQuery } from "-/graphqlTypes";

Other than these two changes, the code looks like it normally would without codegen.

Page Query Example

Let's also use a page query. Again, I have my Gatsby site running with yarn develop, while the code generator runs in the background (yarn codegen:watch).

Create ./src/pages/codegen.tsx with the following code:

./src/pages/codegen.tsxtsx
import React from "react";
import { graphql } from "gatsby";
import { DemoQuery } from "-/graphqlTypes";
interface Props {
data: DemoQuery;
}
const CodegenPage: React.FC<Props> = ({ data }) => {
return (
<>
<p>{data.site.siteMetadata.title}</p>
</>
);
};
export const query = graphql`
query Demo {
site {
siteMetadata {
title
}
}
}
`;
export default CodegenPage;

All the concepts are the same as the hook version. DemoQuery is generated for us as the query is named Demo, which we can then use in our prop types. Sweet!