Skip to main content
mutation

Mutation

mutation OperationName($input: InputType!) { mutationField(input: $input) { id field } }

A GraphQL mutation is a write operation that modifies server-side data. Mutations execute serially – if a document contains multiple mutation fields, they run one after another in declaration order, not in parallel. This guarantees that a mutation that increments a counter followed by a mutation that reads it sees the updated value. Mutations return data just like queries – clients specify the fields they want back in the response.

How it works

Mutations are how GraphQL APIs accept writes. They mirror POST/PUT/PATCH/DELETE semantics in REST, but all writes go through the mutation operation type.

Serial execution: the GraphQL spec §6.3.1 requires that mutation fields at the top level execute serially. This is a hard guarantee – parallel execution of mutations would produce race conditions for sequential operations like 'increment and then read'. Fields nested inside a mutation may still be fetched in parallel.

Input types: mutation arguments typically use Input Object types (keyword input in SDL) rather than regular Object types. This is because Object types can have circular references and resolvers, which input types cannot. Defining a dedicated input type per mutation makes the API explicit and extensible.

Return type design: mutations should return the modified resource, not just a boolean. This allows the client to update its cache without a separate fetch. The Relay specification recommends every mutation return a dedicated payload type with a clientMutationId echo field.

Optimistic updates: because mutations return the modified data, clients (Apollo, urql) can apply optimistic updates immediately and then reconcile with the real server response.

Idempotency: GraphQL does not enforce idempotency on mutations. Design your mutation semantics (createOrUpdate vs create) to match your API contract.

Examples

Create mutation with input type
mutation CreatePost($input: CreatePostInput!) {
  createPost(input: $input) {
    id
    title
    author {
      name
    }
    createdAt
  }
}
Update mutation
mutation UpdateUser($id: ID!, $input: UpdateUserInput!) {
  updateUser(id: $id, input: $input) {
    id
    name
    email
    updatedAt
  }
}
Delete mutation
mutation DeletePost($id: ID!) {
  deletePost(id: $id) {
    success
    deletedId
  }
}
Multiple mutations (serial execution)
mutation BatchOps {
  first:  incrementCounter(by: 1) { value }
  second: incrementCounter(by: 2) { value }
  # first runs to completion before second starts
}
Auth mutation – login
mutation Login($email: String!, $password: String!) {
  login(email: $email, password: $password) {
    token
    expiresAt
    user { id name }
  }
}

Spec Rules

§

Top-level mutation fields execute serially – this is a spec guarantee, not an implementation detail (§6.3.1)

§

Nested fields within a mutation result may be fetched in parallel

§

Use Input Object types for mutation arguments – regular Object types are not allowed as input

§

Return the modified resource, not just a boolean – enables client cache updates without a second fetch

§

Never put mutation logic in a query resolver – side effects in queries violate the spec's intent

§

Multiple mutations in one document require operationName in the request to select which to run

See Also