| name | apollo-client |
| description | writing or modifying GraphQL… |
Apollo Client 3.10
Overview
This skill provides best practices for Apollo Client 3.10 in this codebase, ensuring consistent patterns for GraphQL operations, optimistic UI updates, cache management, and TypeScript type safety.
Quick Reference
Generator Commands
After modifying any operations.graphql file, run the appropriate generator:
bun run generate:types:dev
bun run generate:types:staging
bun run generate:types:production
Note: Replace bun with your project's package manager (npm, yarn, pnpm) as needed.
Import Pattern
All GraphQL types, hooks, and documents must come from generated types:
import {
useGetPlayerQuery,
useUpdatePlayerMutation,
GetPlayerQuery,
PlayerFragment,
ListPlayersDocument,
} from "@/generated/graphql";
Core Rules
1. Only Use Generated Types
Import all GraphQL-related types from @/generated/graphql. Never define manual TypeScript types for GraphQL entities.
import { PlayerFragment, useUpdatePlayerMutation } from "@/generated/graphql";
type Player = { id: string; name: string };
2. Never Modify Generated Files
The generated/graphql.ts file is auto-generated by codegen. To change types:
- Edit the appropriate
operations.graphql file in the feature directory
- Run
bun run generate:types:dev
- Import the newly generated types
3. Always Run Generator After Schema Changes
After modifying any operations.graphql file, immediately run the generator before committing. Verify changes compile with bun run typecheck.
4. Always Include Optimistic Response
Every mutation must include an optimisticResponse for instant UI feedback:
const [updatePlayer] = useUpdatePlayerMutation({
optimisticResponse: variables => ({
__typename: "Mutation",
updatePlayer: {
__typename: "Player",
id: variables.id,
name: variables.input.name,
updatedAt: new Date().toISOString(),
},
}),
});
Key requirements:
- Always include
__typename for every object in the response
- Always include
id for cache normalization
- Use temporary IDs for new objects (e.g.,
crypto.randomUUID())
- Include all fields that the mutation returns
5. Always Update Cache
Every mutation must handle cache updates using one of these strategies:
Automatic Updates - When mutation returns the full entity with id and __typename, Apollo updates automatically. No extra code needed.
cache.modify - For adding/removing items from lists:
const [addPlayer] = useAddPlayerMutation({
optimisticResponse: {
},
update(cache, { data }) {
cache.modify({
fields: {
players(existingPlayers = [], { readField }) {
const newRef = cache.writeFragment({
data: data.addPlayer,
fragment: PlayerFragmentDoc,
});
return [...existingPlayers, newRef];
},
},
});
},
});
refetchQueries - Fallback for complex scenarios:
const [complexMutation] = useComplexMutation({
refetchQueries: ["ListPlayers"],
awaitRefetchQueries: true,
});
Operations.graphql Structure
Fragment-First Pattern
Define fragments before queries/mutations that use them:
fragment PlayerFragment on Player {
id
knownName
firstName
lastName
team {
id
name
}
}
query GetPlayer($id: ID!) {
player(id: $id) {
...PlayerFragment
}
}
mutation UpdatePlayer($id: ID!, $input: UpdatePlayerInput!) {
updatePlayer(id: $id, input: $input) {
...PlayerFragment
}
}
Include Required Fields
Mutations must return all fields needed for cache updates:
mutation AddPlayerToKanban($input: AddPlayerToKanbanInput!) {
addPlayerToKanban(input: $input) {
id
position
notes
kanbanPhaseId
kanbanPhase {
id
name
}
createdAt
updatedAt
}
}
Query Best Practices
Fetch Policies
fetchPolicy: "cache-and-network";
fetchPolicy: "cache-first";
fetchPolicy: "network-only";
Skip When Variables Undefined
const { data } = useGetPlayerQuery({
variables: { id: playerId! },
skip: !playerId,
});
Error Handling
Use onError callback instead of try/catch with console.log:
const [mutation] = useMutation(MUTATION, {
onError: error => {
setErrorState("Failed to update. Please try again.");
},
});
Complete Mutation Pattern
Reference references/mutation-patterns.md for comprehensive examples of the complete mutation pattern including optimistic responses, cache updates, and error handling.
Validation Checklist
When writing or reviewing Apollo code, verify: