All skills
apollographql avatar

/apollo-client

@cb48e40 official
by Apollo GraphQLapollographql/skills115 stars
13

Guide for building React applications with Apollo Client 4.x. Use this skill when: (1) setting up Apollo Client in a React project, (2) writing GraphQL queries or mutations with hooks, (3) configuring caching or cache policies, (4) managing local state with reactive variables, (5) troubleshooting Apollo Client errors or performance issues.

Use this Skill: https://skilld.dev/gh/apollographql/skills/apollo-client

This session only. Nothing lands on disk.

referencesintegration-client.md

≈2.2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Apollo Client Integration for Client-Side Apps

This guide covers setting up Apollo Client in client-side React applications without server-side rendering (SSR). This includes applications using Vite, Parcel, Create React App, or other bundlers that don't implement SSR.

For applications with SSR, use one of the framework-specific integration guides instead:

Installation

npm install @apollo/client graphql rxjs

TypeScript Code Generation (optional but recommended)

For type-safe GraphQL operations with TypeScript, see the TypeScript Code Generation guide.

Setup Steps

Step 1: Create Client

import { ApolloClient, InMemoryCache, HttpLink } from "@apollo/client";

// Recommended: Use HttpOnly cookies for authentication
const httpLink = new HttpLink({
  uri: "https://your-graphql-endpoint.com/graphql",
  credentials: "include", // Sends cookies with requests (secure when using HttpOnly cookies)
});

const client = new ApolloClient({
  link: httpLink,
  cache: new InMemoryCache(),
});

If you need manual token management (less secure, only when HttpOnly cookies aren't available):

import { ApolloClient, InMemoryCache, HttpLink } from "@apollo/client";
import { SetContextLink } from "@apollo/client/link/context";

const httpLink = new HttpLink({
  uri: "https://your-graphql-endpoint.com/graphql",
});

const authLink = new SetContextLink(({ headers }) => {
  const token = localStorage.getItem("token");
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : "",
    },
  };
});

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),
});

Step 2: Setup Provider

import { ApolloProvider } from "@apollo/client";
import App from "./App";

function Root() {
  return (
    <ApolloProvider client={client}>
      <App />
    </ApolloProvider>
  );
}

Step 3: Execute Query

import { gql } from "@apollo/client";
import { useQuery } from "@apollo/client/react";

const GET_USERS = gql`
  query GetUsers {
    users {
      id
      name
      email
    }
  }
`;

function UserList() {
  const { loading, error, data, dataState } = useQuery(GET_USERS);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  // TypeScript note: for stricter type narrowing, you can also check `dataState === "complete"` before accessing data
  return (
    <ul>{data?.users.map((user) => <li key={user.id}>{user.name}</li>)}</ul>
  );
}

Basic Query Usage

Using Variables

const GET_USER = gql`
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }
`;

function UserProfile({ userId }: { userId: string }) {
  const { loading, error, data, dataState } = useQuery(GET_USER, {
    variables: { id: userId },
  });

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  // TypeScript note: for stricter type narrowing, you can also check `dataState === "complete"` before accessing data
  return <div>{data?.user.name}</div>;
}

Note for TypeScript users: Use dataState for more robust type safety and better type narrowing in Apollo Client 4.x.

TypeScript Integration

For complete examples with loading, error handling, and dataState for type narrowing, see Basic Query Usage above.

Usage with Generated Types

For type-safe operations with code generation, see the TypeScript Code Generation guide.

Quick example:

import { gql } from "@apollo/client";
import { useQuery } from "@apollo/client/react";
import { GetUserDocument } from "./queries.generated";

// Define your query with the if (false) pattern for code generation
if (false) {
  gql`
    query GetUser($id: ID!) {
      user(id: $id) {
        id
        name
        email
      }
    }
  `;
}

function UserProfile({ userId }: { userId: string }) {
  // Types are automatically inferred from GetUserDocument
  const { data } = useQuery(GetUserDocument, {
    variables: { id: userId },
  });

  return <div>{data.user.name}</div>;
}
Usage with Manual Type Annotations

If not using code generation, define types alongside your queries using TypedDocumentNode:

import { gql, TypedDocumentNode } from "@apollo/client";
import { useQuery } from "@apollo/client/react";

interface GetUserData {
  user: {
    id: string;
    name: string;
    email: string;
  };
}

interface GetUserVariables {
  id: string;
}

// Types should always be defined via TypedDocumentNode alongside your queries/mutations, not at the useQuery/useMutation call site
const GET_USER: TypedDocumentNode<GetUserData, GetUserVariables> = gql`
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }
`;

function UserProfile({ userId }: { userId: string }) {
  const { data } = useQuery(GET_USER, {
    variables: { id: userId },
  });

  // data.user is automatically typed from GET_USER
  return <div>{data.user.name}</div>;
}

Basic Mutation Usage

import { gql, TypedDocumentNode } from "@apollo/client";
import { useMutation } from "@apollo/client/react";

interface CreateUserMutation {
  createUser: {
    id: string;
    name: string;
    email: string;
  };
}

interface CreateUserMutationVariables {
  input: {
    name: string;
    email: string;
  };
}

const CREATE_USER: TypedDocumentNode<
  CreateUserMutation,
  CreateUserMutationVariables
> = gql`
  mutation CreateUser($input: CreateUserInput!) {
    createUser(input: $input) {
      id
      name
      email
    }
  }
`;

function CreateUserForm() {
  const [createUser, { loading, error }] = useMutation(CREATE_USER);

  const handleSubmit = async (formData: FormData) => {
    const { data } = await createUser({
      variables: {
        input: {
          name: formData.get("name") as string,
          email: formData.get("email") as string,
        },
      },
    });
    if (data) {
      console.log("Created user:", data.createUser);
    }
  };

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault();
        handleSubmit(new FormData(e.currentTarget));
      }}
    >
      <input name="name" placeholder="Name" />
      <input name="email" placeholder="Email" />
      <button type="submit" disabled={loading}>
        {loading ? "Creating..." : "Create User"}
      </button>
      {error && <p>Error: {error.message}</p>}
    </form>
  );
}

Client Configuration Options

const client = new ApolloClient({
  // Required: The cache implementation
  cache: new InMemoryCache({
    typePolicies: {
      Query: {
        fields: {
          // Field-level cache configuration
        },
      },
    },
  }),

  // Network layer
  link: new HttpLink({ uri: "/graphql" }),

  // Avoid defaultOptions if possible as they break TypeScript expectations.
  // Configure options per-query/mutation instead for better type safety.
  // defaultOptions: {
  //   watchQuery: { fetchPolicy: 'cache-and-network' },
  // },

  // DevTools are enabled by default in development
  // Only configure when enabling in production
  devtools: {
    enabled: true, // Only needed for production
  },

  // Custom name for this client instance
  clientAwareness: {
    name: "web-client",
    version: "1.0.0",
  },
});

Important Considerations

  1. Choose Your Hook Strategy: Decide if your application should be based on Suspense. If it is, use suspenseful hooks like useSuspenseQuery (see Suspense Hooks guide), otherwise use non-suspenseful hooks like useQuery (see Queries guide).

  2. Client-Side Only: This setup is for client-side apps without SSR. The Apollo Client instance is created once and reused throughout the application lifecycle.

  3. Authentication: Prefer HttpOnly cookies with credentials: "include" in HttpLink options to avoid exposing tokens to JavaScript. If manual token management is necessary, use SetContextLink to dynamically add authentication headers from localStorage or other client-side storage.

  4. Environment Variables: Store your GraphQL endpoint URL in environment variables for different environments (development, staging, production).

  5. Error Handling: Always handle loading and error states when using useQuery or useLazyQuery. For Suspense-based hooks (useSuspenseQuery), React handles this through <Suspense> boundaries and error boundaries.

Source: SKILL.md on GitHub

1 warning16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill is a comprehensive reference and integration guide for Apollo Client 4.x in React applications. No security vulnerabilities, malicious code, or adversarial patterns were detected.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer7mo

    4/14 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at cb48e40. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 5 months ago
What it can do
Runs commands
metadata
{
  "author": "apollographql",
  "version": "1.0.0"
}
All 1 allowed tools
Bash(npm:*) Bash(npx:*) Bash(node:*) Read Write Edit Glob Grep
Other metadata
compatibility
React 18+, React 19 (Suspense/RSC). Works with Next.js, Vite, CRA, and other React frameworks.
  • React
  • TypeScript
  • apollo-client
  • graphql
  • state-management
  • caching
  • queries
  • mutations
  • suspense

README badge

README badge for apollographql/skills/apollo-client

Guides for building React applications with Apollo Client 4.x, covering queries, mutations, caching, local state, and Suspense integration. Targets React 18+, React 19, Next.js, Vite, and other React frameworks with patterns for client-side apps, server-side rendering, and modern data fetching.

Generated from the current SKILL.md.

Does this skill work with React Server Components and Next.js App Router?
Yes. The skill includes integration guides for Next.js App Router with React Server Components, and supports React 19 with Suspense.
What Apollo Client version does this skill target?
Apollo Client 4.x specifically. The skill does not cover v3 or earlier patterns.
Does this skill cover TypeScript code generation for GraphQL operations?
Yes. The skill includes a reference section on TypeScript Code Generator setup for type-safe operations.
Can I use this skill to configure caching and optimize performance?
Yes. The skill covers InMemoryCache configuration, typePolicies, fetchPolicy strategies, and performance patterns including @defer and @stream.
What frameworks does this skill support beyond client-side React?
It includes integration guides for Next.js App Router, React Router 7 with streaming SSR, and TanStack Start, in addition to client-side apps built with Vite or Create React App.

Generated from the current SKILL.md. These answers refresh after source changes.