Prepared Docs

Prepared Docs

⌘K

    Loading navigation…

User

  1. Working With Data
  2. Graphql Colocation

GraphQL Colocation

Organizing GraphQL files with components using near-operation-file pattern

Now that you know how to write GraphQL operations, let's discuss where to organize them. Colocation keeps your GraphQL files next to the components that use them, improving discoverability and maintainability.

What Colocation Means

In our GraphQL setup, "colocation" refers to the near-operation-file preset pattern where:

  • .graphql files are placed in the same folder as the components that use them
  • Generated TypeScript files (.graphql.ts) are created alongside the .graphql files
  • This is NOT about embedding GraphQL strings directly in component files

This approach, documented in the Guild's near-operation-file guide, provides the best balance of organization and type safety.

Directory Structure

Component-Level Operations

For operations specific to a single component:

Benefits of This Approach

  1. Discoverability: GraphQL operations are right next to the components using them
  2. Maintainability: Easy to update operations when modifying components
  3. Type Safety: Generated types are imported from the same directory
  4. Modularity: Components are self-contained with their data requirements
  5. Refactoring: Moving components automatically moves their GraphQL files

Before and After Examples

❌ Don't do this - Centralized Operations

Old Pattern: All operations in a central location

Problems:

  • Operations disconnected from components
  • Hard to find what queries a component uses
  • Refactoring requires hunting down imports
  • No clear ownership of operations
  • Leads to bloated operations files that request too much data and query too many levels deep.
  • Types become difficult to reason about and maintain.

✅ Do this - Colocated Operations

New Pattern: Operations next to components

Benefits:

  • Clear ownership and organization
  • Easy to see component's data needs
  • Self-contained components
  • Natural code splitting
  • Types are scoped to the component and are easy to reason about

How Generated Files Work

When codegen runs (at the start of pnpm dev, or manually with pnpm turbo run codegen), the near-operation-file preset:

  1. Finds all .graphql files in your app
  2. Generates a .graphql.ts file next to each one
  3. Includes typed document nodes and operation types

Example Generated Output

For this operation:

Generates this TypeScript file:

Important: NOT Inline GraphQL

❌ Don't do this - Inline GraphQL Strings

✅ Do this - Separate .graphql Files

Organizing Complex Components

For components with multiple operations:

Best Practices

✅ Do

  • Place .graphql files in the same folder as components, under src/ of an app, remote, or package
  • Use descriptive names for operation files
  • Group related operations in the same file
  • Give each component its own fragment, named Component_prop, in a fragments.graphql next to it

❌ Don't

  • Put GraphQL strings directly in component files (pnpm lint:graphql rejects gql imports and tags outside tests)
  • Put a .graphql file anywhere codegen does not read, such as a remote's exposes/ directory
  • Name a document anything but queries.graphql, mutations.graphql, subscriptions.graphql, or fragments.graphql
  • Create deeply nested GraphQL folders
  • Share component-specific operations
  • Manually edit generated .graphql.ts files
  • Share one fragment between components: each component declares its own, even when the selections match today
  • Spread a grandchild's fragment into a parent: spread the child's fragment, and let the child spread its own

Cross-Feature Contracts

A fragment belongs to one component. It can appear in more than one place only through its parent:

  • Composition (✅ correct): A parent spreads its direct child's fragment (ChatroomListItem_chatroom spreads ...ChatroomLabel_chatroom). The route's query spreads only the fragment of the component it renders. The route fetches everything in one request, and Apollo's data masking gives each component only the fields in its own fragment.
  • Sharing (❌ avoid): Two components import one fragment, or a query spreads a grandchild's fragment. The components are then coupled: a field that one of them stops reading can't be removed, and a field that one needs is fetched for both.

If two components need the same fields, each declares its own fragment. Duplicated field selections cost nothing: the server merges them.

Next, we'll learn how fragments and data masking work.

Previous

Working with data / GraphQL Operations

Next

Working with data / GraphQL Fragments

On this page

What Colocation Means
Directory Structure
Component-Level Operations
Benefits of This Approach
Before and After Examples
❌ Don't do this - Centralized Operations
✅ Do this - Colocated Operations
How Generated Files Work
Example Generated Output
Important: NOT Inline GraphQL
❌ Don't do this - Inline GraphQL Strings
✅ Do this - Separate .graphql Files
Organizing Complex Components
Best Practices
✅ Do
❌ Don't
Cross-Feature Contracts