Apollo 18: Local State Management
easy⏱ 5 mincourseapollo
Extending the schema locally
Apollo lets you extend your remote schema with local-only types and fields using typeDefs. These fields exist only on the client and are resolved by local resolvers or type policy read functions. You query them with the @client directive: cartItems @client. This unifies local and remote state into one query — a component can fetch a user from the server and the user's UI preferences from local state in the same operation.
import { ApolloClient, InMemoryCache, gql } from '@apollo/client';
const typeDefs = gql`
extend type Query {
cartItems: [CartItem!]!
isDarkMode: Boolean!
}
type CartItem {
id: ID!
name: String!
quantity: Int!
price: Float!
}
`;
const client = new ApolloClient({
uri: '/graphql',
cache: new InMemoryCache(),
typeDefs,
});
Add local-only fields
Define typeDefs that extend Query with cartItems: [CartItem!]! and isDarkMode: Boolean!. Create a CartItem type with id, name, quantity, and price. Use cache.writeQuery to initialize the cart as an empty array. Create a type policy read function for isDarkMode that reads from localStorage. Build a component that queries cartItems @client and displays them, and an addToCart function that uses cache.writeQuery to update the cart.
Mixing local + remote in one query
The @client directive can be applied at the field level, so you can mix local and remote data in a single query. The server fields are fetched normally; the @client fields are resolved locally. This is powerful for UI state that relates to server data — e.g., a product from the server with isInCart @client resolved locally:
query { product(id: $id) { id name price isInCart @client } }
const GET_PRODUCT_WITH_CART_STATUS = gql`
query GetProduct($id: ID!) {
product(id: $id) {
id
name
price
isInCart @client
}
}
`;
// Type policy resolves the local field
const cache = new InMemoryCache({
typePolicies: {
Product: {
fields: {
isInCart: {
read(_, { readField }) {
const id = readField('id');
return cartVar().some(item => item.id === id);
},
},
},
},
},
});
Apollo local state vs Context/Redux
Use Apollo local state when:
- Local state relates to server data (e.g.,
isInCart on a product).
- You want to query local + remote data in one operation.
- The state needs to interact with the Apollo cache.
Use React Context when:
- State is simple and UI-focused (theme, sidebar open/close).
- You don't need GraphQL query integration.
Use Redux/Zustand when:
- You have complex state transitions (state machines, undo/redo).
- State is independent of your GraphQL layer.
Apollo local state shines when it augments server data, not when it replaces a general state manager.