Skip to main content

Working with Mutations

Learn how to write and execute GraphQL mutations to create, update, and delete data.

What is a Mutation?

A mutation is a write operation that modifies data on the server. Mutations are similar to POST, PUT, PATCH, or DELETE requests in REST APIs.

Unlike queries, mutations:

  • Modify data (create, update, delete)
  • Require input objects to specify what to change
  • Return the modified data so you can see the result

Basic Mutation Structure

Every GraphQL mutation follows this structure:

mutation MutationName($input: InputType!) {
mutationField(input: $input) {
returnedField {
subField
}
}
}

Simple Example

mutation CreateItem($input: ItemInput!) {
itemCreate(input: $input) {
item {
_id
title
}
}
}

Variables:

{
"input": {
"title": "New Item",
"price": 29.99
}
}

Mutation Types

Creating Resources

Mutations that create new resources typically follow the pattern resourceCreate:

mutation CreateCollection($input: CollectionInput!) {
collectionCreate(input: $input) {
collection {
_id
title
description
}
}
}

Variables:

{
"input": {
"title": "My Collection",
"description": "A new collection"
}
}

Updating Resources

Mutations that update existing resources typically follow the pattern resourceUpdate:

mutation UpdateItem($id: ID!, $input: ItemInput!) {
itemUpdate(id: $id, input: $input) {
item {
_id
title
price
}
}
}

Variables:

{
"id": "123",
"input": {
"title": "Updated Title",
"price": 39.99
}
}

Deleting Resources

Mutations that delete resources typically follow the pattern resourceDelete:

mutation DeleteItem($id: ID!) {
itemDelete(id: $id) {
success
message
}
}

Variables:

{
"id": "123"
}

Input Types

Mutations use input types to pass complex data. Input types are similar to regular types but are used only for input.

Understanding Input Types

input ItemInput {
title: String!
price: Float
description: String
tags: [String!]
}

Required vs Optional Fields

  • Fields without ! are optional
  • Fields with ! are required
input ItemInput {
title: String! # Required
price: Float # Optional
description: String # Optional
}

Mutation Responses

Mutations return the modified data. Always select the fields you need from the response:

mutation CreateItem($input: ItemInput!) {
itemCreate(input: $input) {
item { # The created item
_id
title
price
}
errors { # Any validation errors
field
message
}
}
}

Common Response Patterns

Return the resource

mutation {
itemCreate(input: $input) {
item { _id title }
}
}

Return success status

mutation {
itemDelete(id: $id) {
success
message
}
}

Return errors

mutation {
itemCreate(input: $input) {
item { _id }
errors {
field
message
}
}
}

Using Variables

Always use variables for mutation inputs:

mutation CreateItem($input: ItemInput!) {
itemCreate(input: $input) {
item {
_id
title
}
}
}

Variables:

{
"input": {
"title": "New Item",
"price": 29.99,
"description": "Item description"
}
}

Partial Updates

For update mutations, you typically only need to include the fields you want to change:

mutation UpdateItem($id: ID!, $input: ItemInput!) {
itemUpdate(id: $id, input: $input) {
item {
_id
title
price
}
}
}

Variables (only update title):

{
"id": "123",
"input": {
"title": "Updated Title"
}
}

Multiple Mutations

You can execute multiple mutations in a single request, but they execute sequentially (not in parallel):

mutation {
first: itemCreate(input: $input1) {
item { _id title }
}
second: itemCreate(input: $input2) {
item { _id title }
}
}

Mutations execute in order, and if one fails, subsequent mutations may not execute.

Best Practices

  • Always use variables - Use variables instead of hardcoding values to make mutations reusable and secure
  • Request returned data - Always request the data you need from mutation responses (e.g., the created item) rather than just a success status
  • Handle errors - Check for errors in mutation responses, including both GraphQL errors and validation errors. See Handling Errors for details
  • Use descriptive names - Name mutations clearly (e.g., CreateUserProfile instead of Mutation1) to help with debugging

Common Patterns

Create with Full Response

mutation CreateItem($input: ItemInput!) {
itemCreate(input: $input) {
item {
_id
title
price
description
createdAt
}
errors {
field
message
}
}
}

Update Specific Fields

mutation UpdateItemPrice($id: ID!, $price: Float!) {
itemUpdate(id: $id, input: { price: $price }) {
item {
_id
price
}
}
}

Delete with Confirmation

mutation DeleteItem($id: ID!) {
itemDelete(id: $id) {
success
message
}
}

Batch Operations

mutation CreateMultipleItems($inputs: [ItemInput!]!) {
item1: itemCreate(input: $inputs[0]) {
item { _id title }
}
item2: itemCreate(input: $inputs[1]) {
item { _id title }
}
}

Error Handling

Mutations can return errors in several ways:

GraphQL Errors

Errors in the errors array indicate problems with the mutation itself:

{
"data": null,
"errors": [
{
"message": "Unauthorized",
"extensions": {
"code": "UNAUTHORIZED"
}
}
]
}

Validation Errors

Some mutations return validation errors in the response:

{
"data": {
"itemCreate": {
"item": null,
"errors": [
{
"field": "price",
"message": "Price must be greater than 0"
}
]
}
}
}

Handling Both Types

Mutations can return errors in two ways:

  • GraphQL errors in the errors array (e.g., UNAUTHORIZED, UNAUTHENTICATED)
  • Validation errors in the mutation response (e.g., field-level validation errors)

Always check for both types. See Handling Errors for detailed error handling patterns.

Common Mistakes

  • Missing required fields - Ensure all required fields (marked with !) are included in the input. The API will reject mutations with missing required fields
  • Not using variables - Avoid hardcoding values in mutations. Use variables to make mutations reusable and prevent security issues
  • Not requesting returned data - Request the data you need from mutation responses (e.g., the created item) rather than just a success status

Summary

  • Mutations are write operations that modify data
  • Always use input types with variables
  • Request returned data from mutation responses
  • Handle errors (both GraphQL and validation errors)
  • Use descriptive mutation names for debugging

Next Steps