Join us for GraphQL Summit, October 10-12 in San Diego. Use promo code ODYSSEY for $400 off your pass.
Launch GraphOS Studio

Using GraphQL directives in Apollo Client

Configure GraphQL fields and fragments

A decorates part of a GraphQL or with additional configuration. Tools like Apollo Client can read a GraphQL document's directives and perform custom logic as appropriate.

s are preceded by the @ character, like so:

query myQuery($someTest: Boolean) {
experimentalField @skip(if: $someTest)

This example shows the @skip , which is a built-in directive (i.e., it's part of the GraphQL specification). It demonstrates the following about s:

  • s can take s of their own (if in this case).
  • s appear after the declaration of what they decorate (the experimentalField in this case).


The @client allows you to resolve client-only data alongside your server data. These s are not sent to the GraphQL server.

query LaunchDetails($launchId: ID!) {
launch(id: $launchId) {
rocket {
# resolved locally on the client,
# removed from the request to the server
description @client

For more information about the @client , see this section on local-only fields. The @client is also useful for client schema mocking before a given is supported in the GraphQL API your application is consuming.


The @connection allows you to specify a custom cache key for paginated results. For more information, see this section on the @connection directive.

query Feed($offset: Int, $limit: Int) {
feed(offset: $offset, limit: $limit) @connection(key: "feed") {


Beginning with version 3.7.0, Apollo Client provides preview support for the @defer directive. This enables your queries to receive data for specific s incrementally, instead of receiving all data at the same time. This is helpful whenever some fields in a query take much longer to resolve than others.

To use the @defer , we apply it to an inline or named that contains all slow-resolving s:

query PersonQuery($personId: ID!) {
person(id: $personId) {
# Basic fields (fast)
# Friend fields (slower)
... @defer {
friends {

Note: in order to use @defer in a React Native application, additional configuration is required. See the React Native docs for more information.

For more information about the @defer , check out the @defer docs.


If your GraphQL query uses s, the local-only s of that query can provide the values of those variables.

To do so, you apply the @export(as: "variableName") , like so:

query CurrentAuthorPostCount($authorId: Int!) {
currentAuthorId @client @export(as: "authorId")
postCount(authorId: $authorId)

In the query above, the result of the local-only currentAuthorId is used as the value of the $authorId that's passed to postCount.

You can do this even if postCount is also a local-only (i.e., if it's also marked as @client).

For more information and other considerations when using the @export , check out the local-only fields docs.

Since 3.8.0

The @nonreactive can be used to mark query s or spreads and is used to indicate that changes to the data contained within the subtrees marked @nonreactive should not trigger rerendering. This allows parent components to fetch data to be rendered by their children without rerendering themselves when the data corresponding with s marked as @nonreactive change.

Consider an App component that fetches and renders a list of ski trails:

const TrailFragment = gql`
fragment TrailFragment on Trail {
const ALL_TRAILS = gql`
query allTrails {
allTrails {
...TrailFragment @nonreactive
function App() {
const { data, loading } = useQuery(ALL_TRAILS);
return (
<h2>Ski Trails</h2>
{data? => (
<Trail key={} id={} />

The Trail component renders a trail's name and status and allows the user to execute a to toggle the status of the trail between "OPEN" and "CLOSED":

const Trail = ({ id }) => {
const [updateTrail] = useMutation(UPDATE_TRAIL);
const { data } = useFragment({
fragment: TrailFragment,
from: {
__typename: "Trail",
return (
<li key={id}>
{} - {data.status}
checked={data.status === "OPEN" ? true : false}
onChange={(e) => {
variables: {
trailId: id,
status: ? "OPEN" : "CLOSED",

Notice that the Trail component isn't receiving the entire trail object via props, only the id which is used along with the document to create a live binding for each trail item in the cache. This allows each Trail component to react to the cache updates for a single trail independently. Updates to a trail's status will not cause the parent App component to rerender since the @nonreactive is applied to the TrailFragment spread, a that includes the status .

Error handling
Edit on GitHubEditForumsDiscord