All skills
apollographql avatar

/graphql-operations

@194056e official
by Apollo GraphQLapollographql/skills115 stars
13

Guide for writing GraphQL operations (queries, mutations, fragments) following best practices. Use this skill when: (1) writing GraphQL queries or mutations, (2) organizing operations with fragments, (3) optimizing data fetching patterns, (4) setting up type generation or linting, (5) reviewing operations for efficiency.

Use this Skill: https://skilld.dev/gh/apollographql/skills/graphql-operations

This session only. Nothing lands on disk.

referencesfragments.md

≈1.9k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Fragment Patterns

This reference covers patterns for organizing and using GraphQL fragments effectively.

Table of Contents

Fragment Basics

Defining Fragments

fragment UserBasicInfo on User {
  id
  name
  avatarUrl
}

Using Fragments

query GetUser($id: ID!) {
  user(id: $id) {
    ...UserBasicInfo
    email
  }
}

fragment UserBasicInfo on User {
  id
  name
  avatarUrl
}

Fragment Spread

The ... operator spreads fragment fields:

query GetPost($id: ID!) {
  post(id: $id) {
    id
    title
    author {
      ...UserBasicInfo # Spreads id, name, avatarUrl
    }
  }
}

Fragment Colocation

Colocate with Components

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

Component Owns Its Data

// 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" />;
}

Parent Composes Fragments

// 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>
  );
}

Query Uses Component Fragments

// 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>
  );
}

Fragment Reuse

Shared Fragments

For common patterns used across many components:

# fragments/common.graphql

fragment Timestamps on Node {
  createdAt
  updatedAt
}

fragment PageInfoFields on PageInfo {
  hasNextPage
  hasPreviousPage
  startCursor
  endCursor
}

Domain-Specific Fragments

# 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
}

Using Shared Fragments

query GetPost($id: ID!) {
  post(id: $id) {
    id
    title
    ...Timestamps
    author {
      ...UserSummary
    }
  }
}

Inline Fragments

Anonymous Inline Fragments

For grouping fields with directives:

query GetUser($id: ID!, $includeDetails: Boolean!) {
  user(id: $id) {
    id
    name
    ... @include(if: $includeDetails) {
      email
      bio
      website
    }
  }
}

Inline Fragments on Interfaces

query GetNodes($ids: [ID!]!) {
  nodes(ids: $ids) {
    id
    ... on User {
      name
      email
    }
    ... on Post {
      title
      content
    }
  }
}

Type Conditions

Fragments on Union Types

query Search($query: String!) {
  search(query: $query) {
    ... on User {
      id
      name
      avatarUrl
    }
    ... on Post {
      id
      title
      excerpt
    }
    ... on Comment {
      id
      body
      post {
        id
        title
      }
    }
  }
}

Named Fragments for Unions

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
  }
}

Handling __typename

function SearchResult({ result }) {
  switch (result.__typename) {
    case 'User':
      return <UserResult user={result} />;
    case 'Post':
      return <PostResult post={result} />;
    case 'Comment':
      return <CommentResult comment={result} />;
  }
}

Fragment Composition

Building Up Fragments

# 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
  }
}

Fragments in Fragments

fragment CommentWithAuthor on Comment {
  id
  body
  createdAt
  author {
    ...UserSummary
  }
}

fragment PostWithComments on Post {
  id
  title
  comments(first: 10) {
    edges {
      node {
        ...CommentWithAuthor
      }
    }
  }
}

Fragment Spread Order

Order doesn't matter - fields are merged:

query GetUser($id: ID!) {
  user(id: $id) {
    ...UserProfile
    ...UserStats
    # Both fragments' fields are included
  }
}

Anti-Patterns

Avoid Giant Fragments

# 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
}

Avoid Unused Fragment Fields

# 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
}

Avoid Deeply Nested Fragments

# 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
  }
}

Avoid Circular Fragment Dependencies

# 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: SKILL.md on GitHub

1 warning2d5 checks · Risk SAFE
  • Gen Agent Trust Hub2d

    The skill is a comprehensive guide for writing GraphQL operations and setting up associated development tools. It contains only instructional content and standard developer workflow examples. No security risks were identified.

  • Socket2d

    No alerts

  • Snyk2d

    Risk: LOW · No issues

  • Runlayer7mo

    6/6 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 194056e. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 2 days ago
What it can do
Runs commands
compatibility
Any GraphQL client (Apollo Client, urql, Relay, etc.)
metadata
{
  "author": "apollographql",
  "version": "1.0.1"
}
All 1 allowed tools
Bash(npm:*) Bash(npx:*) Read Write Edit Glob Grep
  • graphql
  • queries
  • mutations
  • fragments
  • apollo-client
  • type-generation
  • best-practices
  • variables

README badge

README badge for apollographql/skills/graphql-operations

Teaches best practices for writing GraphQL operations (queries, mutations, subscriptions) and organizing them with fragments. Covers naming conventions, variable usage, field selection optimization, and colocating fragments with components across Apollo Client and other GraphQL clients.

Generated from the current SKILL.md.

Does this skill work with Apollo Client, urql, and other GraphQL clients?
Yes. The skill covers GraphQL operation best practices that apply to any GraphQL client library, including Apollo Client, urql, Relay, and others.
Does this skill include code generation or type safety setup?
The skill mentions type generation and linting as areas it addresses, with references to a tooling documentation file, but focuses primarily on writing and organizing operations by hand.
Can I use this skill for subscriptions?
Yes. The skill covers queries, mutations, and subscriptions equally, with examples and naming conventions for each.
Does this skill help optimize data fetching?
Yes. It includes principles like requesting only the fields you need, using fragments to avoid duplication, and leveraging directives like @include and @skip for conditional fetching.

Generated from the current SKILL.md. These answers refresh after source changes.