On this page

TypeScript React-Query

GraphQL Code Generator plugin for generating React Query hooks. Supports TypeScript and Flow.

Version
7.0.5
Weekly downloads
361k
License
MIT
Updated
Jun 23, 2026

Installation

          npm i -D @graphql-codegen/typescript-react-query
        

Config API Reference

fetcher

type: object

Customize the fetcher you wish to use in the generated file. React-Query is agnostic to the data-fetching layer, so you should provide it, or use a custom one.

The following options are available to use:

  • ‘fetch’ - requires you to specify endpoint and headers on each call, and uses fetch to do the actual http call.
  • { endpoint: string, fetchParams: RequestInit }: hardcode your endpoint and fetch options into the generated output, using the environment fetch method. You can also use process.env.MY_VAR as endpoint or header value.
  • file#identifier - You can use custom fetcher method that should implement the exported ReactQueryFetcher interface. Example: ./my-fetcher#myCustomFetcher.
  • graphql-request: Will generate each hook with client argument, where you should pass your own GraphQLClient (created from graphql-request).

exposeDocument

type: boolean

For each generate query hook adds document field with a corresponding GraphQL query. Useful for queryClient.fetchQuery. Default value: “false”

exposeQueryKeys

type: boolean

For each generate query hook adds getKey(variables: QueryVariables) function. Useful for cache updates. If addInfiniteQuery is true, it will also add a getKey function to each infinite query. Default value: “false”

exposeMutationKeys

type: boolean

For each generate mutation hook adds getKey() function. Useful for call outside of functional component. Default value: “false”

exposeFetcher

type: boolean

For each generate query hook adds fetcher field with a corresponding GraphQL query using the fetcher. It is useful for queryClient.fetchQuery and queryClient.prefetchQuery. Default value: “false”

errorType

type: string

Changes the default “TError” generic type. Default value: “unknown”

addInfiniteQuery

type: boolean

Adds an Infinite Query along side the standard one Default value: “false”

legacyMode

type: boolean

If false, it will work with @tanstack/react-query, default value is true. Default value: “true”

namingConvention

type: object

Allow you to override the naming convention of the output. You can either override all namings, or specify an object with specific custom naming convention per output. The format of the converter must be a valid module#method. Allowed values for specific output are: typeNames, enumValues. You can also use “keep” to keep all GraphQL names as-is. Additionally, you can set transformUnderscore to true if you want to override the default behavior, which is to preserve underscores.

Available case functions in change-case-all are camelCase, capitalCase, constantCase, dotCase, headerCase, noCase, paramCase, pascalCase, pathCase, sentenceCase, snakeCase, lowerCase, localeLowerCase, lowerCaseFirst, spongeCase, titleCase, upperCase, localeUpperCase and upperCaseFirst See more Default value: “change-case-all#pascalCase”

operationResultSuffix

type: string

Adds a suffix to generated operation result type names Default value: ""

dedupeOperationSuffix

type: boolean

Set this configuration to true if you wish to make sure to remove duplicate operation name suffix. Default value: “false”

omitOperationSuffix

type: boolean

Set this configuration to true if you wish to disable auto add suffix of operation name, like Query, Mutation, Subscription, Fragment. Default value: “false”

documentVariablePrefix

type: string

Changes the GraphQL operations variables prefix. Default value: ""

documentVariableSuffix

type: string

Changes the GraphQL operations variables suffix. Default value: “Document”

fragmentVariablePrefix

type: string

Changes the GraphQL fragments variables prefix. Default value: ""

fragmentVariableSuffix

type: string

Changes the GraphQL fragments variables suffix. Default value: “FragmentDoc”

pureMagicComment

type: boolean

This config adds PURE magic comment to the static variables to enforce treeshaking for your bundler. Default value: “false”

optimizeDocumentNode

type: boolean

If you are using documentNode: documentMode | documentNodeImportFragments, you can set this to true to apply document optimizations for your GraphQL document. This will remove all “loc” and “description” fields from the compiled document, and will remove all empty arrays (such as directives, arguments and variableDefinitions). Default value: “true”

experimentalFragmentVariables

type: boolean

If set to true, it will enable support for parsing variables on fragments. Default value: “false”

scalars

type: object

Extends or overrides the built-in scalars and custom GraphQL scalars to a custom type.

typesPrefix

type: string

Prefixes all the generated types. Default value: ""

typesSuffix

type: string

Suffixes all the generated types. Default value: ""

nonOptionalTypename

type: boolean

Automatically adds __typename field to the generated types, even when they are not specified in the selection set, and makes it non-optional Default value: “false”

inlineFragmentTypes

type: string

Whether fragment types should be inlined into other operations. “inline” is the default behavior and will perform deep inlining fragment types within operation type definitions. “combine” is the previous behavior that uses fragment type references without inlining the types (and might cause issues with deeply nested fragment that uses list types). Default value: “inline”

emitLegacyCommonJSImports

type: boolean

Emit legacy common js imports. Default it will be true this way it ensure that generated code works with non-compliant bundlers. Default value: “true”

strictScalars

type: boolean

Makes scalars strict.

If scalars are found in the schema that are not defined in scalars an error will be thrown during codegen. Default value: “false”

defaultScalarType

type: string

Allows you to override the type that unknown scalars will have. Default value: “any”

skipTypename

type: boolean

Does not add __typename to the generated types, unless it was specified in the selection set. Default value: “false”

dedupeFragments

type: boolean

Removes fragment duplicates for reducing data transfer. It is done by removing sub-fragments imports from fragment definition Instead - all of them are imported to the Operation node. Default value: “false”

Usage Examples

Using default fetch

By default, this plugin will generate a fetcher based on the environment global fetch definition.

codegen.ts
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  schema: 'MY_SCHEMA_PATH',
  documents: './src/**/*.graphql',
  generates: {
    './generates.ts': {
      plugins: ['typescript-operations', 'typescript-react-query'],
      config: {
        fetcher: 'fetch'
      }
    }
  }
}
export default config

To use the generated hooks, import it, and then specify the endpoint and optionally fetchParams:

import { useMyQuery } from './generated'

export const MyComponent = () => {
  const { status, data, error, isFetching } = useMyQuery({
    endpoint: 'http://localhost:3000/graphql',
    fetchParams: {
      headers: {
        'My-Header': 'XYZ'
      }
    }
  })
}

Using fetch with Codegen configuration

If you wish to avoid specifying endpoint and fetchParams on each hook usage, you can specify those in the codegen.yml file:

codegen.ts
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  schema: 'MY_SCHEMA_PATH',
  documents: './src/**/*.graphql',
  generates: {
    './generates.ts': {
      plugins: ['typescript-operations', 'typescript-react-query'],
      config: {
        fetcher: {
          endpoint: 'http://localhost:3000/graphql',
          fetchParams: {
            headers: {
              'My-Header': 'SomeValue'
            }
          }
        }
      }
    }
  }
}
export default config

And if you wish to have more control over the value, or even provide it in runtime, you can use environment variables:

codegen.ts
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  schema: 'MY_SCHEMA_PATH',
  documents: './src/**/*.graphql',
  generates: {
    './generates.ts': {
      plugins: ['typescript-operations', 'typescript-react-query'],
      config: {
        fetcher: {
          endpoint: 'process.env.ENDPOINT'
        }
      }
    }
  }
}
export default config

You can even use a custom variable from your code, and add custom imports with add plugin:

codegen.ts
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  schema: 'MY_SCHEMA_PATH',
  documents: './src/**/*.graphql',
  generates: {
    './generates.ts': {
      plugins: [
        {
          add: {
            content: "import { endpointUrl, fetchParams } from './my-config';"
          }
        },
        'typescript',
        'typescript-operations',
        'typescript-react-query'
      ],
      config: {
        fetcher: {
          endpoint: 'endpointUrl',
          fetchParams: 'fetchParams'
        }
      }
    }
  }
}
export default config

The generated hooks doesn’t require you to specify anything, you can just use it as-is:

import { useMyQuery } from './generated'

export const MyComponent = () => {
  const { status, data, error, isFetching } = useMyQuery({})
}

Using graphql-request

If you are using graphql-request, you can set fetcher to graphql-request, and then the generated React Hook will expect you to pass the GraphQLClient instance (created by graphql-request library).

codegen.ts
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  schema: 'MY_SCHEMA_PATH',
  documents: './src/**/*.graphql',
  generates: {
    './generates.ts': {
      plugins: ['typescript-operations', 'typescript-react-query'],
      config: {
        fetcher: 'graphql-request'
      }
    }
  }
}
export default config

And the, while using, provide your client instance:

import { useMyQuery } from './generated'
import { client } from './my-graphql-request-client'

export const MyComponent = () => {
  const { status, data, error, isFetching } = useMyQuery(client, {})
}

Using Custom Fetcher

If you wish to create a custom fetcher, you can provide your own function as a Mapper string (file#identifier). Codegen will take care of importing it and use it as a fetcher.

codegen.ts
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  schema: 'MY_SCHEMA_PATH',
  documents: './src/**/*.graphql',
  generates: {
    './generates.ts': {
      plugins: ['typescript-operations', 'typescript-react-query'],
      config: {
        fetcher: {
          func: './my-file#myFetcher',
          isReactHook: false // optional, defaults to false, controls the function's signature. Read below
        }
      }
    }
  }
}
export default config

As a shortcut, the fetcher property may also directly contain the function as a mapper string:

# …
config:
  fetcher: './my-file#myFetcher' # isReactHook is false here (the default version)

Codegen will use myFetcher, and you can just use the hook directly:

import { useMyQuery } from './generated'

export const MyComponent = () => {
  const { status, data, error, isFetching } = useMyQuery({})
}

Depending on the isReactHook property, your myFetcher should be in the following signature:

  • isReactHook: false
    type MyFetcher<TData, TVariables> = (operation: string, variables?: TVariables, options?: RequestInit['headers']): (() => Promise<TData>)
  • isReactHook: true
    type MyFetcher<TData, TVariables> = (operation: string, options?: RequestInit['headers']): ((variables?: TVariables) => Promise<TData>)

Usage example (isReactHook: false)

export const fetchData = <TData, TVariables>(
  query: string,
  variables?: TVariables,
  options?: RequestInit['headers']
): (() => Promise<TData>) => {
  return async () => {
    const res = await fetch('https://api.url', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        ...options
      },
      body: JSON.stringify({
        query,
        variables
      })
    })

    const json = await res.json()

    if (json.errors) {
      const { message } = json.errors[0] || {}
      throw new Error(message || 'Error…')
    }

    return json.data
  }
}

Usage example (isReactHook: true)

export const useFetchData = <TData, TVariables>(
  query: string,
  options?: RequestInit['headers']
): ((variables?: TVariables) => Promise<TData>) => {
  // it is safe to call React Hooks here.
  const { url, headers } = React.useContext(FetchParamsContext)

  return async (variables?: TVariables) => {
    const res = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        ...headers,
        ...options
      },
      body: JSON.stringify({
        query,
        variables
      })
    })

    const json = await res.json()

    if (json.errors) {
      const { message } = json.errors[0] || {}
      throw new Error(message || 'Error…')
    }

    return json.data
  }
}

Using Infinite Query

If you wish to use infinite query for pagination or infinite scroll you can with the addInfiniteQuery config setting. This will however setup an infinite query for every request whether in reality it can do it or not.

To use this you need to return an object of new queries, and it blends them in to the query.

Usage example (addInfiniteQuery: true)

with the following query:

query AnimalsQuery($catsRange: Int, $catsStarting: Int, $dogsRange: Int, $dogsStarting: Int) {
  cats(range: $catsRange, starting: $catsStarting) {
    # …
  }
  dogs(range: $dogsRange, starting: $dogsStarting) {
    # …
  }
}
import { useInfiniteMyQuery } from './generated'

export const MyComponent = () => {
  const { status, data, error, isFetching } = useInfiniteAnimalsQuery(
    {
      catsRange: 5,
      catsStarting: 0,
      dogsRange: 10,
      dogsStarting: 0
    },
    {
      getNextPageParam(lastPage, allPages) {
        const totalLocal = (allPages.length ?? 0) * (queryParams.limit ?? 1)
        const totalDogs = lastPage.dogs.items?.length ?? 0
        if (totalLocal < totalDogs) {
          return {
            catsStarting: totalLocal * 5,
            dogsStarting: totalLocal * 10
          }
        }
      }
    }
  )
}