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.
Setting up your project
Install the following packages. This installation assumes you already have installed @apollo/client
and its dependencies.
1npm install -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations
Recommended starter configuration
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.
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;
codegen.ts
. Use the method that best fits your project's needs.Finally, we'll add the script to our package.json
file:
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
:
$ 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.
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;
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.
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.
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.
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.
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.
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;
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.
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}