graphql-operations

Guide for writing GraphQL operations (queries, mutations, fragments) following best practices. Use this skill when: (1) writing GraphQL queries or mutations,…

INSTALLATION
npx skills add https://github.com/apollographql/skills --skill graphql-operations
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

GraphQL Operations Guide

This guide covers best practices for writing GraphQL operations (queries, mutations, subscriptions) as a client developer. Well-written operations are efficient, type-safe, and maintainable.

Start From the Schema

Write every operation against the project's schema, not against the examples in this guide.

  • Find the schema before you write anything. Check the schema entry in codegen.ts, graphql.config.*, or apollo.config.*, then look for *.graphql SDL files.
  • Use only the fields, arguments, and enum values that the schema defines. Field names in this guide, such as updatedAt or orderBy: { field: CREATED_AT, direction: DESC }, are illustrations.
  • Save the operation as a document next to the client's existing operations. Leave the server schema unchanged unless the user asks for a schema change.

Operation Basics

Query Structure

query GetUser($id: ID!) {

  user(id: $id) {

    id

    name

    email

  }

}

Mutation Structure

mutation CreatePost($input: CreatePostInput!) {

  createPost(input: $input) {

    id

    title

    createdAt

  }

}

Subscription Structure

subscription OnMessageReceived($channelId: ID!) {

  messageReceived(channelId: $channelId) {

    id

    content

    sender {

      id

      name

    }

  }

}

Quick Reference

Operation Naming

PatternExample
QueryGetUser, ListPosts, SearchProducts
MutationCreateUser, UpdatePost, DeleteComment
SubscriptionOnMessageReceived, OnUserStatusChanged

Variable Syntax

# Required variable

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

# Optional variable with default

query ListPosts($first: Int = 20) { ... }

# Multiple variables

query SearchPosts($query: String!, $status: PostStatus, $first: Int = 10) { ... }

Fragment Syntax

# Define fragment

fragment UserBasicInfo on User {

  id

  name

  avatarUrl

}

# Use fragment

query GetUser($id: ID!) {

  user(id: $id) {

    ...UserBasicInfo

    email

  }

}

Directives

query GetUser($id: ID!, $includeEmail: Boolean!) {

  user(id: $id) {

    id

    name

    email @include(if: $includeEmail)

  }

}

query GetPosts($skipDrafts: Boolean!) {

  posts {

    id

    title

    draft @skip(if: $skipDrafts)

  }

}

Key Principles

1. Request Only What You Need

# Good: Specific fields

query GetUserName($id: ID!) {

  user(id: $id) {

    id

    name

  }

}

# Avoid: Over-fetching

query GetUser($id: ID!) {

  user(id: $id) {

    id

    name

    email

    bio

    posts {

      id

      title

      content

      comments {

        id

      }

    }

    followers {

      id

      name

    }

    # ... many unused fields

  }

}

2. Name All Operations

# Good: Named operation

query GetUserPosts($userId: ID!) {

  user(id: $userId) {

    posts {

      id

      title

    }

  }

}

# Avoid: Anonymous operation

query {

  user(id: "123") {

    posts {

      id

      title

    }

  }

}

3. Use Variables, Not Inline Values

# Good: Variables

query GetUser($id: ID!) {

  user(id: $id) {

    id

    name

  }

}

# Avoid: Hardcoded values

query {

  user(id: "123") {

    id

    name

  }

}

4. Colocate Fragments with Components

// UserAvatar.tsx

export const USER_AVATAR_FRAGMENT = gql`

  fragment UserAvatar on User {

    id

    name

    avatarUrl

  }

`;

function UserAvatar({ user }) {

  return <img src={user.avatarUrl} alt={user.name} />;

}

Reference Files

Detailed documentation for specific topics:

  • Queries - Query patterns and optimization
  • Mutations - Mutation patterns and error handling
  • Fragments - Fragment organization and reuse
  • Tooling - Code generation and linting

Ground Rules

  • ALWAYS read the project's schema first, and use only the fields, arguments, and enum values it defines
  • ALWAYS name your operations (no anonymous queries/mutations)
  • ALWAYS use variables for dynamic values
  • ALWAYS request only the fields you need
  • ALWAYS include id field for cacheable types
  • NEVER hardcode values in operations
  • NEVER duplicate field selections across files
  • PREFER fragments for reusable field selections
  • PREFER colocating fragments with components
  • USE descriptive operation names that reflect purpose
  • USE @include/@skip for conditional fields
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card