GraphQL Schema Patterns

GraphQL queries, mutations, and code generation patterns. Use when creating GraphQL operations, working with Apollo Client, or generating types

What Is This

The GraphQL Schema Patterns skill provides a set of conventions and technical patterns for defining, organizing, and consuming GraphQL queries and mutations in modern TypeScript/React codebases. It is designed to streamline the workflow of creating GraphQL operations, integrating with tools such as Apollo Client, and leveraging code generation for type safety. This skill prescribes strict rules for how to structure .gql files, utilize generated TypeScript hooks, and manage error handling, ensuring consistency and maintainability in teams working with GraphQL APIs.

Key elements of this skill include:

  • Prohibiting inline gql literals in source files
  • Mandating the use of external .gql files for all operations
  • Requiring automatic code generation for TypeScript types and hooks
  • Standardizing error handling in mutations
  • Organizing queries and mutations for predictable imports and reusability

Why Use It

GraphQL offers significant flexibility, but without clear patterns, teams can quickly encounter problems such as:

  • Inconsistent query definitions scattered across the codebase
  • Type mismatches leading to runtime errors
  • Duplicated or boilerplate Apollo hook logic
  • Difficulties in refactoring or maintaining large applications

Adopting the GraphQL Schema Patterns skill addresses these issues by:

  1. Ensuring Type Safety: Automatic code generation produces strongly-typed hooks and result objects, reducing bugs and improving editor support.
  2. Improving Maintainability: Centralized .gql files keep operations easy to locate, review, and reuse.
  3. Reducing Boilerplate: Generated hooks encapsulate complex query and mutation logic, minimizing repetitive code.
  4. Enforcing Robust Error Handling: Required onError handlers prevent silent failures and improve user feedback.
  5. Enhancing Team Collaboration: Consistent file and naming conventions make it easier for teams to onboard and contribute effectively.

How to Use It

To implement the GraphQL Schema Patterns skill in your project, follow these core steps:

1. Create .gql Files for All Operations

Never define GraphQL queries or mutations inline with the gql template literal. Instead, create dedicated .gql files corresponding to each operation. For example:

## src/components/ItemList/GetItems.gql
query GetItems($limit: Int, $offset: Int) {
  items(limit: $limit, offset: $offset) {
    id
    name
    description
    createdAt
  }
}

This approach keeps your operations modular and discoverable.

2. Run Code

Generation

After creating or editing .gql files, always run the GraphQL code generator to produce TypeScript types and Apollo Client hooks. This ensures that your code stays in sync with the latest schema and query changes.

npm run gql:typegen

This command will generate files such as:

src/components/ItemList/GetItems.generated.ts

These files contain strongly-typed hooks based on your GraphQL operations.

3. Use Generated Hooks

Exclusively

Do not write raw useQuery, useMutation, or useSubscription hooks directly. Instead, import and use the generated hooks, which encapsulate your operation and provide typed results.

import { useGetItemsQuery } from './GetItems.generated';

const ItemList = () => {
  const { data, loading, error, refetch } = useGetItemsQuery({
    variables: { limit: 20, offset: 0 },
  });

  if (error) return <ErrorState error={error} onRetry={refetch} />;
  if (loading && !data) return <LoadingSkeleton />;
  if (!data?.items.length) return <EmptyState />;

  return <List items={data.items} />;
};

4. Always

Add onError Handlers to Mutations

When using generated mutation hooks, always provide an onError handler to manage failure cases proactively:

import { useCreateItemMutation } from './CreateItem.generated';

const [createItem] = useCreateItemMutation({
  onError: (error) => {
    // Handle error (e.g., show toast or log)
    alert(error.message);
  },
});

5. Organize Files

Consistently

Adopt a clear directory and file structure to separate concerns and improve code navigation. For example:

src/
├── components/
│   └── ItemList/
│       ├── ItemList.tsx
│       ├── GetItems.gql
│       └── GetItems.generated.ts
└── graphql/
    └── mutations/
        └── CreateItem.gql

Queries and mutations should live close to their consumers or in shared locations as appropriate.

When to Use It

Apply the GraphQL Schema Patterns skill in the following scenarios:

  • Creating New GraphQL Operations: Whenever you need to define a new query, mutation, or subscription, use external .gql files and follow the code generation workflow.
  • Integrating with Apollo Client: Use generated hooks for all GraphQL data fetching and mutations in React components.
  • Refactoring Existing Code: When migrating legacy code, refactor inline gql literals into .gql files and switch to generated hooks.
  • Enabling Type-safe Code Generation: Use this pattern whenever you want to leverage automatic TypeScript type generation for improved code reliability.

Important Notes

  • Never edit generated files: All .generated.ts files are auto-generated. Any manual changes will be lost when codegen runs.
  • Always run codegen: After any changes to .gql files, run the code generator to keep types and hooks up to date.
  • Do not inline gql literals: Inline literals lead to duplication and can bypass type safety.
  • Always handle errors: Missing onError handlers can result in unhandled promise rejections and poor user experience.
  • Keep operations small and focused: Large queries can hurt performance and make maintenance harder.

By following these patterns and rules, you will achieve a more robust, maintainable, and scalable GraphQL codebase, with strong guarantees for correctness and team productivity.