apollo-client
SKILL.md
Apollo Client 4.x Guide
Apollo Client is a comprehensive state management library for JavaScript that enables you to manage both local and remote data with GraphQL. Version 4.x brings improved caching, better TypeScript support, and React 19 compatibility.
Quick Start
Step 1: Install
npm install @apollo/client graphql
For TypeScript type generation (recommended):
npm install -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typed-document-node
Step 2: Create Client
import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client';
const client = new ApolloClient({
link: new HttpLink({
uri: 'https://your-graphql-endpoint.com/graphql',
headers: {
authorization: localStorage.getItem('token') || '',
},
}),
cache: new InMemoryCache(),
});
Step 3: Setup Provider
import { ApolloProvider } from '@apollo/client';
import App from './App';
function Root() {
return (
<ApolloProvider client={client}>
<App />
</ApolloProvider>
);
}
Step 4: Execute Query
import { useQuery, gql } from '@apollo/client';
const GET_USERS = gql`
query GetUsers {
users {
id
name
email
}
}
`;
function UserList() {
const { loading, error, data } = useQuery(GET_USERS);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{data.users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Basic Query Usage
Using Variables
const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`;
function UserProfile({ userId }: { userId: string }) {
const { loading, error, data } = useQuery(GET_USER, {
variables: { id: userId },
});
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return <div>{data.user.name}</div>;
}
TypeScript Integration
interface User {
id: string;
name: string;
email: string;
}
interface GetUserData {
user: User;
}
interface GetUserVariables {
id: string;
}
const { data } = useQuery<GetUserData, GetUserVariables>(GET_USER, {
variables: { id: userId },
});
// data.user is typed as User
Basic Mutation Usage
import { useMutation, gql } from '@apollo/client';
const CREATE_USER = gql`
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
id
name
email
}
}
`;
function CreateUserForm() {
const [createUser, { loading, error }] = useMutation(CREATE_USER);
const handleSubmit = async (formData: FormData) => {
const { data } = await createUser({
variables: {
input: {
name: formData.get('name'),
email: formData.get('email'),
},
},
});
console.log('Created user:', data.createUser);
};
return (
<form onSubmit={(e) => { e.preventDefault(); handleSubmit(new FormData(e.currentTarget)); }}>
<input name="name" placeholder="Name" />
<input name="email" placeholder="Email" />
<button type="submit" disabled={loading}>
{loading ? 'Creating...' : 'Create User'}
</button>
{error && <p>Error: {error.message}</p>}
</form>
);
}
Client Configuration Options
const client = new ApolloClient({
// Required: The cache implementation
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
// Field-level cache configuration
},
},
},
}),
// Network layer
link: new HttpLink({ uri: '/graphql' }),
// Default options for queries/mutations
defaultOptions: {
watchQuery: {
fetchPolicy: 'cache-and-network',
errorPolicy: 'all',
},
query: {
fetchPolicy: 'network-only',
errorPolicy: 'all',
},
mutate: {
errorPolicy: 'all',
},
},
// Enable Apollo DevTools (development only)
connectToDevTools: process.env.NODE_ENV === 'development',
// Custom name for this client instance
name: 'web-client',
version: '1.0.0',
});
Reference Files
Detailed documentation for specific topics:
- Queries - useQuery, useLazyQuery, polling, refetching
- Mutations - useMutation, optimistic UI, cache updates
- Caching - InMemoryCache, typePolicies, cache manipulation
- State Management - Reactive variables, local state
- Error Handling - Error policies, error links, retries
- Troubleshooting - Common issues and solutions
Key Rules
Query Best Practices
- Always handle
loadinganderrorstates in UI - Use
fetchPolicyto control cache behavior per query - Colocate queries with components that use them
- Use fragments to share fields between queries
Mutation Best Practices
- Update cache after mutations (don't rely on refetching everything)
- Use optimistic responses for better UX
- Handle errors gracefully in the UI
- Use
refetchQueriessparingly (prefer cache updates)
Caching Best Practices
- Configure
keyFieldsfor types withoutidfield - Use
typePoliciesfor pagination and computed fields - Understand cache normalization to debug issues
- Use Apollo DevTools to inspect cache state
Performance
- Avoid over-fetching with proper field selection
- Use
useLazyQueryfor user-triggered queries - Configure appropriate
fetchPolicyper use case - Use
@deferand@streamfor large responses
Ground Rules
- ALWAYS use Apollo Client 4.x patterns (not v3 or earlier)
- ALWAYS wrap your app with
ApolloProvider - ALWAYS handle loading and error states
- NEVER store Apollo Client in React state (use module-level or context)
- PREFER
cache-firstfor read-heavy data,network-onlyfor real-time data - USE TypeScript for better type safety with GraphQL
- IMPLEMENT proper cache updates instead of refetching entire queries
- USE Apollo DevTools during development to debug cache issues
Weekly Installs
14
Repository
apollographql/skillsInstalled on
claude-code13
opencode5
codex5
gemini-cli5
cursor4
goose4