Setting the file. One moment.
Subchapter 10.1
references/fragments.mdMarkdown7 KBView on GitHub
This reference covers patterns for organizing and using GraphQL fragments effectively.
fragment UserBasicInfo on User {
id
name
avatarUrl
}query GetUser($id: ID!) {
user(id: $id) {
...UserBasicInfo
email
}
}
fragment UserBasicInfo on User {
id
name
avatarUrl
}The ... operator spreads fragment fields:
query GetPost($id: ID!) {
post(id: $id) {
id
title
author {
...UserBasicInfo # Spreads id, name, avatarUrl
}
}
}Keep fragments next to the components that use them:
src/
components/
UserAvatar/
UserAvatar.tsx
UserAvatar.fragment.graphql
UserCard/
UserCard.tsx
UserCard.fragment.graphql
PostList/
PostList.tsx
PostList.query.graphql// UserAvatar.tsx
import { gql } from "@apollo/client";
export const USER_AVATAR_FRAGMENT = gql`
fragment UserAvatar on User {
id
name
avatarUrl
}
`;
interface UserAvatarProps {
user: UserAvatarFragment;
}
export function UserAvatar({ user }: UserAvatarProps) {
return <img src={user.avatarUrl} alt={user.name} className="avatar" />;
}// UserCard.tsx
import { gql } from "@apollo/client";
import { USER_AVATAR_FRAGMENT, UserAvatar } from "./UserAvatar";
export const USER_CARD_FRAGMENT = gql`
fragment UserCard on User {
id
name
bio
...UserAvatar
}
${USER_AVATAR_FRAGMENT}
`;
export function UserCard({ user }: { user: UserCardFragment }) {
return (
<div className="user-card">
<UserAvatar user={user} />
<h3>{user.name}</h3>
<p>{user.bio}</p>
</div>
);
}// UserProfile.tsx
import { gql, useQuery } from "@apollo/client";
import { USER_CARD_FRAGMENT, UserCard } from "./UserCard";
const GET_USER = gql`
query GetUserProfile($id: ID!) {
user(id: $id) {
...UserCard
email
createdAt
}
}
${USER_CARD_FRAGMENT}
`;
export function UserProfile({ userId }: { userId: string }) {
const { data } = useQuery(GET_USER, { variables: { id: userId } });
if (!data) return null;
return (
<div>
<UserCard user={data.user} />
<p>Email: {data.user.email}</p>
</div>
);
}For common patterns used across many components:
# fragments/common.graphql
fragment Timestamps on Node {
createdAt
updatedAt
}
fragment PageInfoFields on PageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}# fragments/user.graphql
fragment UserSummary on User {
id
name
avatarUrl
}
fragment UserProfile on User {
...UserSummary
bio
location
website
socialLinks {
platform
url
}
}
fragment UserWithStats on User {
...UserSummary
followerCount
followingCount
postCount
}query GetPost($id: ID!) {
post(id: $id) {
id
title
...Timestamps
author {
...UserSummary
}
}
}For grouping fields with directives:
query GetUser($id: ID!, $includeDetails: Boolean!) {
user(id: $id) {
id
name
... @include(if: $includeDetails) {
email
bio
website
}
}
}query GetNodes($ids: [ID!]!) {
nodes(ids: $ids) {
id
... on User {
name
email
}
... on Post {
title
content
}
}
}query Search($query: String!) {
search(query: $query) {
... on User {
id
name
avatarUrl
}
... on Post {
id
title
excerpt
}
... on Comment {
id
body
post {
id
title
}
}
}
}query Search($query: String!) {
search(query: $query) {
...SearchResultUser
...SearchResultPost
...SearchResultComment
}
}
fragment SearchResultUser on User {
id
name
avatarUrl
}
fragment SearchResultPost on Post {
id
title
excerpt
author {
name
}
}
fragment SearchResultComment on Comment {
id
body
post {
id
title
}
}function SearchResult({ result }) {
switch (result.__typename) {
case 'User':
return <UserResult user={result} />;
case 'Post':
return <PostResult post={result} />;
case 'Comment':
return <CommentResult comment={result} />;
}
}# Base fragment
fragment PostCore on Post {
id
title
slug
}
# Extended fragment
fragment PostPreview on Post {
...PostCore
excerpt
featuredImage {
url
}
}
# Full fragment
fragment PostFull on Post {
...PostPreview
content
publishedAt
author {
...UserSummary
}
tags {
id
name
}
}fragment CommentWithAuthor on Comment {
id
body
createdAt
author {
...UserSummary
}
}
fragment PostWithComments on Post {
id
title
comments(first: 10) {
edges {
node {
...CommentWithAuthor
}
}
}
}Order doesn’t matter - fields are merged:
query GetUser($id: ID!) {
user(id: $id) {
...UserProfile
...UserStats
# Both fragments' fields are included
}
}# Bad: Too many fields, not all needed everywhere
fragment UserEverything on User {
id
name
email
bio
avatarUrl
coverImage
website
location
socialLinks { ... }
posts { ... }
followers { ... }
following { ... }
# ... 50 more fields
}
# Good: Focused fragments for specific uses
fragment UserAvatar on User {
id
name
avatarUrl
}
fragment UserProfile on User {
id
name
bio
avatarUrl
website
location
}# Bad: Component only uses name and avatarUrl
fragment UserInfo on User {
id
name
email # unused
avatarUrl
bio # unused
website # unused
}
# Good: Only request what's needed
fragment UserInfo on User {
id
name
avatarUrl
}# Bad: Hard to understand what's being fetched
fragment Level1 on User {
...Level2
}
fragment Level2 on User {
...Level3
}
fragment Level3 on User {
...Level4
}
# ... continues
# Good: Keep nesting shallow
fragment UserWithPosts on User {
id
name
posts {
...PostPreview
}
}# Bad: Circular reference (won't work)
fragment UserWithPosts on User {
posts {
...PostWithAuthor
}
}
fragment PostWithAuthor on Post {
author {
...UserWithPosts # Circular!
}
}
# Good: Break the cycle
fragment UserWithPosts on User {
posts {
...PostPreview
}
}
fragment PostWithAuthor on Post {
author {
...UserSummary # Different fragment, no cycle
}
}Source