Apollo 3: Fragments & Composition
easy⏱ 5 mincourseapollo
Reusable field selections
A fragment defines a set of fields on a specific GraphQL type. Instead of repeating id name email avatar in every query, you define it once: fragment UserFields on User { id name email avatar }. Then spread it: ...UserFields. Fragments are the foundation of component-driven data fetching — each component declares exactly the data it needs.
const USER_FIELDS = gql`
fragment UserFields on User {
id
name
email
avatar
}
`;
const GET_USERS = gql`
query GetUsers {
users {
...UserFields
}
}
${USER_FIELDS}
`;
Create and compose fragments
Define a USER_FIELDS fragment on User with id, name, email, and avatar. Define a POST_FIELDS fragment on Post with id, title, createdAt. Compose both in a GET_USER_WITH_POSTS query that selects user(id: $id) { ...UserFields posts { ...PostFields } }. Use both fragments with ${USER_FIELDS} and ${POST_FIELDS} interpolation.
Colocation pattern
The colocation pattern means defining a fragment next to the component that uses its fields. UserAvatar defines UserAvatar.fragments = { user: gql'fragment UserAvatarUser on User { id avatar name }' }. The parent query includes the fragment via interpolation. This way, when UserAvatar needs a new field, you only change one file.
// UserAvatar.tsx
export const USER_AVATAR_FRAGMENT = gql`
fragment UserAvatarFields on User {
id
avatar
name
}
`;
// Parent query
const GET_USERS = gql`
query GetUsers {
users { ...UserAvatarFields }
}
${USER_AVATAR_FRAGMENT}
`;
Fragment masking benefits
Modern GraphQL clients (like Apollo with codegen) support fragment masking: a component can only access fields from its own fragment, not from the parent query. This enforces data isolation — UserAvatar cannot accidentally depend on fields from UserBio's fragment. It makes refactoring safer and component boundaries clearer.