Optimistic Updates
When you know what a mutation will return assuming everything goes right, you can apply the change to the cache immediately rather than waiting for the server. Pass an optimisticResponse as the second argument to mutate:
<script> import { graphql } from '$houdini'
let { itemID }: { itemID: string } = $props()
const toggle = graphql(` mutation ToggleItem($id: ID!) { toggleItem(id: $id) { item { id checked } } } `)
function toggleItem() { toggle.mutate({ id: itemID }, { optimisticResponse: { toggleItem: { item: { id: itemID, checked: true } } } }) }</script>
<button onclick={toggleItem}> toggle item</button>When the mutation resolves, the optimistic values are replaced with the real response. If the mutation fails, the optimistic changes are reverted and the promise rejects with the error.
Always include id in your selection when using optimistic responses so the cache knows which record to update. You don’t need to provide a complete response; the cache will write whatever fields you include.
Optimistic Keys
Sometimes it's not possible to know the ID to provide in an optimistic response. Most commonly, this happens when creating a new record and inserting the result into a list:
mutation CreateTodoItem($text: String!) { createItem(text: $text) { item { id # <--- what goes here? text ...All_Items_insert } }}To handle this, mark the id field with @optimisticKey and Houdini will generate a temporary ID for you:
mutation CreateTodoItem($text: String!) { createItem(text: $text) { item { id @optimisticKey text ...All_Items_insert } }}With @optimisticKey, you no longer need to provide an id in the optimisticResponse. Houdini generates one, immediately inserts the record into the list, and replaces the temporary ID with the real one when the mutation resolves.
The important distinction from making up your own ID is that Houdini tracks these generated keys internally. If you were to reference the generated key in another mutation before the create resolves (say, to mark the new item as complete), the second mutation will block until the real ID comes back from the server.
If your record's key is a custom scalar that Houdini can't generate, you'll need to supply the value manually in optimisticResponse.
Why is TypeScript Missing Fields?
The generated types for optimistic responses don’t include fields from fragments you’ve spread in. This is intentional: tightly coupling a mutation invocation to a fragment defined elsewhere creates a fragile dependency. If the fragment changes, the type mismatch won’t surface until runtime.
The safe practice is to duplicate any fields you need in the mutation’s own selection set.