GraphQL Codegen

How to generate TypeScript types for your application


Manually creating types for your GraphQL operations is error prone. As you introduce change, it becomes cumbersome to maintain correct types across your entire application. Additionally, changes to your schema might cause changes to your existing operations. This becomes difficult to track and maintain.

Instead, you can generate your TypeScript definitions automatically with GraphQL Code Generator using your application's schema to ensure type accuracy.

This guide provides detail on how to set up GraphQL Codegen in your application to provide types for your GraphQL operations.

note
This article covers GraphQL Codegen installation and configuration. If you'd like to learn how Apollo Client integrates with TypeScript more generally, read the TypeScript with Apollo Client guide.

Setting up your project

Install the following packages. This installation assumes you already have installed @apollo/client and its dependencies.

Bash
1npm install -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations

Next, we'll create a configuration file for GraphQL Code Generator, named codegen.ts, at the root of our project. The following is a recommended minimal configuration for Apollo Client apps.

TypeScript
codegen.ts
1import { CodegenConfig } from "@graphql-codegen/cli";
2
3const config: CodegenConfig = {
4  overwrite: true,
5  schema: "<URL_OF_YOUR_GRAPHQL_API>",
6  // This assumes that all your source files are in a top-level `src/` directory - you might need to adjust this to your file structure
7  documents: ["src/**/*.{ts,tsx}"],
8  // Don't exit with non-zero status when there are no documents
9  ignoreNoDocuments: true,
10  generates: {
11    // Use a path that works the best for the structure of your application
12    "./src/types/__generated__/graphql.ts": {
13      plugins: ["typescript", "typescript-operations"],
14      config: {
15        avoidOptionals: {
16          // Use `null` for nullable fields instead of optionals
17          field: true,
18          // Allow nullable input fields to remain unspecified
19          inputValue: false,
20        },
21        // Use `unknown` instead of `any` for unconfigured scalars
22        defaultScalarType: "unknown",
23        // Apollo Client always includes `__typename` fields
24        nonOptionalTypename: true,
25        // Apollo Client doesn't add the `__typename` field to root types so
26        // don't generate a type for the `__typename` for root operation types.
27        skipTypeNameForRoot: true,
28      },
29    },
30  },
31};
32
33export default config;
note
There are multiple ways to specify a schema in your codegen.ts. Use the method that best fits your project's needs.

Finally, we'll add the script to our package.json file:

JSON
package.json
1{
2  "scripts": {
3    "codegen": "graphql-codegen --config codegen.ts"
4  }
5}

Running the script generates types based on the schema file or GraphQL API you provided in codegen.ts:

Bash
$ npm run codegen
 Parse Configuration
 Generate outputs

A note about the client preset

If you follow GraphQL Codegen's quickstart guide, it recommends generating your config file using the GraphQL Code Generator CLI. This wizard installs and configures the @graphql-codegen/client-preset.

We do not recommend using the client preset with Apollo Client apps because it generates additional runtime code that adds bundle size to your application and includes features that are incompatible with Apollo Client. Instead, we recommend using the typescript and typescript-operations plugins directly (at minimum), which focus on only generating types and don't include additional runtime code. Follow the steps in the preceding section to use a setup that includes these plugins.

If you're already using the client preset, or you choose to use it instead of working directly with the plugins, we recommend the following minimal configuration for Apollo Client apps.

TypeScript
1import { CodegenConfig } from "@graphql-codegen/cli";
2
3const config: CodegenConfig = {
4  overwrite: true,
5  schema: "<URL_OF_YOUR_GRAPHQL_API>",
6  // This assumes that all your source files are in a top-level `src/` directory - you might need to adjust this to your file structure
7  documents: ["src/**/*.{ts,tsx}", "!src/gql/**/*"],
8  // Don't exit with non-zero status when there are no documents
9  ignoreNoDocuments: true,
10  generates: {
11    // Use a path that works the best for the structure of your application
12    "./src/gql/": {
13      preset: "client",
14      presetConfig: {
15        // Disable fragment masking
16        fragmentMasking: false,
17      },
18      config: {
19        avoidOptionals: {
20          // Use `null` for nullable fields instead of optionals
21          field: true,
22          // Allow nullable input fields to remain unspecified
23          inputValue: false,
24        },
25        // Use `unknown` instead of `any` for unconfigured scalars
26        defaultScalarType: "unknown",
27        // Apollo Client always includes `__typename` fields
28        nonOptionalTypename: true,
29        // Apollo Client doesn't add the `__typename` field to root types so
30        // don't generate a type for the `__typename` for root operation types.
31        skipTypeNameForRoot: true,
32      },
33    },
34  },
35};
36
37export default config;
caution
This configuration disables fragment masking in the client preset because it's incompatible with Apollo Client's data masking functionality. If you are using the generated useFragment function or anything generated from the fragment masking feature, you need to migrate away from it to use data masking in Apollo Client. See the guide on data masking for more information on using TypeScript with Apollo Client's data masking feature, including instructions on how to migrate away from GraphQL Codegen's fragment masking feature.

Advanced GraphQL Codegen configuration

Generating relative types files

As your application scales, a single types file that contains all operation types might become unwieldy. The near-operation-file-preset makes it possible to generate an operation types file relative to the file where the operation is defined.

Bash
1npm install -D @graphql-codegen/near-operation-file-preset

The following is a recommended minimal configuration. See the near-operation-file-preset documentation for additional configuration options, such as customizing the file name or extension.

TypeScript
codegen.ts
1import { CodegenConfig } from "@graphql-codegen/cli";
2
3const config: CodegenConfig = {
4  overwrite: true,
5  schema: "<URL_OF_YOUR_GRAPHQL_API>",
6  // This assumes that all your source files are in a top-level `src/` directory - you might need to adjust this to your file structure
7  documents: ["src/**/*.{ts,tsx}"],
8  // Don't exit with non-zero status when there are no documents
9  ignoreNoDocuments: true,
10  generates: {
11    "./src/types/__generated__/graphql.ts": {
12      plugins: ["typescript"],
13    },
14    "./src/": {
15      preset: "near-operation-file",
16      presetConfig: {
17        // This should be the file generated by the "typescript" plugin above,
18        // relative to the directory specified for this configuration
19        baseTypesPath: "./types/__generated__/graphql.ts",
20      },
21      plugins: ["typescript-operations"],
22      // Note: these config options moved from the other generated file config
23      config: {
24        avoidOptionals: {
25          // Use `null` for nullable fields instead of optionals
26          field: true,
27          // Allow nullable input fields to remain unspecified
28          inputValue: false,
29        },
30        // Use `unknown` instead of `any` for unconfigured scalars
31        defaultScalarType: "unknown",
32        // Apollo Client always includes `__typename` fields
33        nonOptionalTypename: true,
34        // Apollo Client doesn't add the `__typename` field to root types so
35        // don't generate a type for the `__typename` for root operation types.
36        skipTypeNameForRoot: true,
37      },
38    },
39  },
40};
41
42export default config;

Usage

The following example imports the generated types relative to the current file.

TypeScript
my-component.ts
1import { useQuery, TypedDocumentNode } from "@apollo/client/react";
2// The query name and path might differ depending on your codegen config
3import {
4  GetRocketInventoryQuery,
5  GetRocketInventoryQueryVariables,
6} from "./my-component.generated";
7
8const GET_ROCKET_INVENTORY: TypedDocumentNode<
9  GetRocketInventoryQuery,
10  GetRocketInventoryQueryVariables
11> = gql`
12  query GetRocketInventory($year: Int!) {
13    rocketInventory(year: $year) {
14      id
15      model
16      year
17      stock
18    }
19  }
20`;
21
22function MyComponent() {
23  const { data } = useQuery(GET_ROCKET_INVENTORY, {
24    //    ^? GetRocketInventoryQuery | undefined;
25    variables: { year: 2025 },
26  });
27
28  // ...
29}

Generating precompiled GraphQL documents with their type definitions

The gql template literal tag is used in Apollo Client apps to define GraphQL documents for use with Apollo Client APIs. Its purpose is to parse the GraphQL string into a standard GraphQL AST. Parsing occurs when the module is executed which adds startup time to your application. Additionally, the GraphQL document returned by gql is typed as a DocumentNode which doesn't include type information about its data or variables.

The typed-document-node plugin makes it possible to generate precompiled GraphQL documents preconfigured with the TypedDocumentNode type.

Bash
1npm install -D @graphql-codegen/typed-document-node

The following is a recommended minimal configuration which uses the near-operation-file-preset configuration from the previous section. If you don't use near-operation-file-preset, add the plugin to the file config that uses the typescript-operations plugin.

TypeScript
codegen.ts
1import { CodegenConfig } from "@graphql-codegen/cli";
2
3const config: CodegenConfig = {
4  overwrite: true,
5  schema: "<URL_OF_YOUR_GRAPHQL_API>",
6  // This assumes that all your source files are in a top-level `src/` directory - you might need to adjust this to your file structure
7  documents: ["src/**/*.{ts,tsx}"],
8  // Don't exit with non-zero status when there are no documents
9  ignoreNoDocuments: true,
10  generates: {
11    "./src/types/__generated__/graphql.ts": {
12      plugins: ["typescript"],
13    },
14    "./src/": {
15      preset: "near-operation-file",
16      presetConfig: {
17        // This should be the file generated by the "typescript" plugin above,
18        // relative to the directory specified for this configuration
19        baseTypesPath: "./types/__generated__/graphql.ts",
20      },
21      plugins: ["typescript-operations", "typed-document-node"],
22      // Note: these config options moved from the other generated file config
23      config: {
24        avoidOptionals: {
25          // Use `null` for nullable fields instead of optionals
26          field: true,
27          // Allow nullable input fields to remain unspecified
28          inputValue: false,
29        },
30        // Use `unknown` instead of `any` for unconfigured scalars
31        defaultScalarType: "unknown",
32        // Apollo Client always includes `__typename` fields
33        nonOptionalTypename: true,
34        // Apollo Client doesn't add the `__typename` field to root types so
35        // don't generate a type for the `__typename` for root operation types.
36        skipTypeNameForRoot: true,
37      },
38    },
39  },
40};
41
42export default config;
note
You might need to change the structure of your application to avoid bundling the query more than once in your application. If you author GraphQL documents using the gql template tag, you won't consume the returned GraphQL document since you'll import and use the precompiled document generated by this plugin instead.

You may need to tweak your bundler settings to strip out unused variables from your bundle. Alternatively you can author GraphQL operations in .graphql files.

Usage

The following example imports the query definition from the generated file.

TypeScript
my-component.ts
1import { useQuery } from "@apollo/client/react";
2// The query name and path might differ depending on your codegen config
3import { getRocketInventoryQuery } from "./my-component.generated";
4
5function MyComponent() {
6  const { data } = useQuery(getRocketInventoryQuery, {
7    //    ^? GetRocketInventoryQuery | undefined;
8    variables: { year: 2025 },
9  });
10
11  // ...
12}
Feedback

Edit on GitHub

Ask Community