obsidian/wiki/payloadcms/graphql-extending.md
2026-05-15 15:46:16 +01:00

4.1 KiB

title aliases tags sources created updated
GraphQL — Custom Queries and Mutations
graphql-custom-resolvers
extending-graphql
payloadcms
graphql
queries
mutations
resolvers
raw/graphql__extending.md
2026-05-15 2026-05-15

Overview

Payload exposes two config keys for adding custom GraphQL operations, both receiving (GraphQL, payload) as arguments:

Config Path Description
graphQL.queries Function returning object of custom query definitions
graphQL.mutations Function returning object of custom mutation definitions

Critical: use the GraphQL and payload instances provided via arguments — never install your own graphql package alongside Payload.

Defining Custom Operations

import { buildConfig } from 'payload'
import myCustomQueryResolver from './graphql/queries/myCustomQuery/resolver'

export default buildConfig({
  graphQL: {
    queries: (GraphQL, payload) => ({
      MyCustomQuery: {
        type: new GraphQL.GraphQLObjectType({
          name: 'MyCustomQuery',
          fields: {
            text: { type: GraphQL.GraphQLString },
            someNumberField: { type: GraphQL.GraphQLFloat },
          },
        }),
        args: {
          argNameHere: {
            type: new GraphQL.GraphQLNonNull(GraphQL.GraphQLString),
          },
        },
        resolve: myCustomQueryResolver,
      },
    }),
  },
})

Resolver Function

Resolvers receive four arguments:

async (obj, args, context, info) => {}
Arg Description
obj Previous object — rarely used, usually discarded
args Query/mutation arguments (must be declared in the operation first)
context { req, res } — gives access to payload, user, and other request state
info Schema info + contextual data about the running operation

Gotcha: set depth: 0 when returning data directly from the Local API so GraphQL can correctly resolve nested relationship values.

Useful Types & Utilities

import { GraphQLJSON, GraphQLJSONObject } from '@payloadcms/graphql/types'
import { GraphQL } from '@payloadcms/graphql/types'
import { buildPaginatedListType } from '@payloadcms/graphql/types'

buildPaginatedListType

Creates a paginated result type matching Payload's generated schema:

type: buildPaginatedListType(
  'AuthorPosts',                              // must be unique
  payload.collections['posts'].graphQL?.type, // GraphQL type for items
)

payload.collections[slug].graphQL

Access auto-generated types per collection:

graphQL?: {
  type: GraphQLObjectType
  paginatedType: GraphQLObjectType
  JWT: GraphQLObjectType
  versionType: GraphQLObjectType
  whereInputType: GraphQLInputObjectType
  mutationInputType: GraphQLNonNull<any>
  updateMutationInputType: GraphQLNonNull<any>
}
src/graphql/
  queries/
    index.ts
    myCustomQuery/
      index.ts
      resolver.ts
  mutations/

Key Takeaways

  • Add custom ops via graphQL.queries / graphQL.mutations in buildConfig — both are functions receiving (GraphQL, payload).
  • Never install graphql independently — use the provided GraphQL argument to avoid version conflicts.
  • Resolver signature: (obj, args, context, info)context.req carries payload and user.
  • Use depth: 0 in Local API calls inside resolvers to avoid double-population.
  • Re-use Payload's auto-generated types via payload.collections[slug].graphQL — avoids type duplication.
  • buildPaginatedListType produces a Payload-compatible paginated response type.
  • Group all custom GraphQL logic under src/graphql/ — queries and mutations in separate sub-folders.

Source: raw/graphql__extending.md — https://payloadcms.com/docs/graphql/extending