Writing queries, mutations, and subscriptions with typed document nodes
Operations are how you interact with the GraphQL API. We use typed document nodes instead of auto-generated hooks, providing better flexibility and type safety.
Now that you understand the architecture and key concepts, let's learn how to write GraphQL operations. This section covers queries, mutations, and subscriptions—the core ways you interact with the GraphQL API.
Old Pattern: Using generated hooks
Problems:
New Pattern: Using document nodes with useQuery
Benefits:
GraphQL enums are generated as TypeScript const enums, providing type safety for all enum values.
Our codegen configuration uses enumsAsConst: true, which generates:
This provides:
A mutation can fail, and the user needs to see that it did. Show a failure state (here, the mutation's own error). Call logger.errorAndReport only for an error the backend cannot have reported, such as a network or transport failure or an unexpected exception in your own code. An error the server returned in the response (CombinedGraphQLErrors.is(error)) is already in the backend's telemetry, and reporting it again from the browser costs money and adds nothing.
Problem: Extracting types from query results using TypeScript indexed access
Issues:
Partial improvement: You can use NonNullable to handle nullability (NonNullable<Query["field"]>["subfield"]), but this still has the same limitations. See the Fragments guide for the full migration path, including the null-safe extraction pattern and the final fragment-based solution.
pnpm lint:graphql fails with @graphql-eslint/no-unused-variables
All operations must be named for better debugging and tooling:
Naming conventions:
Get or describe the data (e.g., GetUser, SearchIncidents)UpdateChatroom, CreateIncident)On (e.g., OnChatroomUpdate, OnMessageReceived)The lint gate enforces PascalCase names, camelCase variables, the On prefix for subscriptions, and no Query/Mutation/Subscription/Fragment suffix: codegen appends those, so an operation named ThingsQuery would generate ThingsQueryQuery. The Get prefix and the mutation verb are conventions that nothing enforces: neither lint nor a review agent checks them, so follow them in code review.
For better UX, use optimistic updates with mutations:
Once you're comfortable writing operations, the next section covers where to organize them using the colocation pattern.
On this page