What are Mutations
A reader finishes The Salt Road and leaves a five-star review. That is not a read: it changes data on the server. In GraphQL, writes get their own operation type, the mutation, so everyone reading the code knows that this request has side effects.
The rule
Queries read, mutations write; both answer with a selection.
The schema lists writes on a separate root type, Mutation. Their arguments are usually grouped into an input type, declared with input instead of type:
input AddReviewInput {
bookId: ID!
rating: Int!
text: String
}
type Mutation {
addReview(input: AddReviewInput!): Review!
updatePrice(bookId: ID!, price: Float!): Book!
}A client calls one with the mutation keyword, and, just like a query, selects fields from what comes back:
mutation AddReview($input: AddReviewInput!) {
addReview(input: $input) {
id
rating
book {
title
reviews(first: 3) { rating }
}
}
}{ "input": { "bookId": "b1", "rating": 5, "text": "Could not put it down." } }Things to notice:
- The
mutationkeyword is required. The{ ... }shorthand always means a query, so{ addReview(...) }would look foraddReviewonQueryand fail. - The response is a normal selection. Asking for the new review's
idand the book's latest ratings lets the page refresh in the same trip, and client caches update the stored book automatically. - Input types are for data going in; object types are for data coming out. You cannot pass a
Reviewas an argument, and you cannot select fields from anAddReviewInput.
Nothing in the language physically stops a query resolver from writing data, but doing so breaks everyone's expectations: clients retry and cache queries freely. Keep side effects in mutations.
The shortcut
For any user action, ask "does this change anything on the server?" Yes → mutation. Then ask "what does the screen need to show next?" and select exactly that.
Does it change data?
Yes, a new review is stored. Use
mutation.
Drills
Answer fast — trust the rule.
A reader changes their display name. Which operation type should the app use?
Why is { addReview(input: $input) { id } } rejected?
Why select book { reviews(first: 3) { rating } } in the mutation's response?
Which can be used as the type of a mutation argument?
Remember
- Queries read, mutations write; both answer with a selection.
- Changes data →
mutation; then select what the screen needs next. - Trap: the shorthand
{ }is only for queries, and object types cannot be arguments.
