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-tanstack-start.md

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

Apollo Client Integration with TanStack Start

This guide covers integrating Apollo Client in a TanStack Start application with support for modern streaming SSR.

Note: When using npx create-tsrouter-app to create a new TanStack Start application, you can choose Apollo Client in the setup wizard to have all of this configuration automatically set up for you.

Installation

Install Apollo Client and the TanStack Start integration package:

npm install @apollo/client-integration-tanstack-start @apollo/client graphql rxjs

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

Setup

Step 1: Configure Root Route with Context

In your routes/__root.tsx, change from createRootRoute to createRootRouteWithContext to provide the right context type:

import type { ApolloClientIntegration } from "@apollo/client-integration-tanstack-start";
import {
  createRootRouteWithContext,
  Outlet,
} from "@tanstack/react-router";

export const Route = createRootRouteWithContext<ApolloClientIntegration.RouterContext>()({
  component: RootComponent,
});

function RootComponent() {
  return (
    <html>
      <head>
        <meta charSet="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>My App</title>
      </head>
      <body>
        <Outlet />
      </body>
    </html>
  );
}

Step 2: Set Up Apollo Client in Router

In your router.tsx, set up your Apollo Client instance and run routerWithApolloClient:

import {
  routerWithApolloClient,
  ApolloClient,
  InMemoryCache,
} from "@apollo/client-integration-tanstack-start";
import { HttpLink } from "@apollo/client";
import { createRouter } from "@tanstack/react-router";
import { routeTree } from "./routeTree.gen";

export function getRouter() {
  const apolloClient = new ApolloClient({
    cache: new InMemoryCache(),
    link: new HttpLink({ uri: "https://your-graphql-endpoint.com/graphql" }),
  });

  const router = createRouter({
    routeTree,
    context: {
      ...routerWithApolloClient.defaultContext,
    },
  });

  return routerWithApolloClient(router, apolloClient);
}

Important: ApolloClient and InMemoryCache must be imported from @apollo/client-integration-tanstack-start, not from @apollo/client.

Usage

Option 1: Loader with preloadQuery and useReadQuery

Use the preloadQuery function in your route loader to preload data during navigation:

import { gql } from "@apollo/client";
import { useReadQuery } from "@apollo/client/react";
import { createFileRoute } from "@tanstack/react-router";
import type { TypedDocumentNode } from "@apollo/client";

// TypedDocumentNode definition with types
const GET_USER: TypedDocumentNode<
  { user: { id: string; name: string; email: string } },
  { id: string }
> = gql`
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }
`;

export const Route = createFileRoute("/user/$userId")({
  component: RouteComponent,
  loader: ({ context: { preloadQuery }, params }) => {
    const queryRef = preloadQuery(GET_USER, {
      variables: { id: params.userId },
    });

    return {
      queryRef,
    };
  },
});

function RouteComponent() {
  const { queryRef } = Route.useLoaderData();
  const { data } = useReadQuery(queryRef);

  return (
    <div>
      <h1>{data.user.name}</h1>
      <p>{data.user.email}</p>
    </div>
  );
}

Option 2: Direct useSuspenseQuery in Component

You can also use Apollo Client's suspenseful hooks directly in your component without a loader:

import { gql } from "@apollo/client";
import { useSuspenseQuery } from "@apollo/client/react";
import { createFileRoute } from "@tanstack/react-router";
import type { TypedDocumentNode } from "@apollo/client";

// TypedDocumentNode definition with types
const GET_POSTS: TypedDocumentNode<{
  posts: Array<{ id: string; title: string; content: string }>;
}> = gql`
  query GetPosts {
    posts {
      id
      title
      content
    }
  }
`;

export const Route = createFileRoute("/posts")({
  component: RouteComponent,
});

function RouteComponent() {
  const { data } = useSuspenseQuery(GET_POSTS);

  return (
    <div>
      <h1>Posts</h1>
      <ul>
        {data.posts.map((post) => (
          <li key={post.id}>
            <h2>{post.title}</h2>
            <p>{post.content}</p>
          </li>
        ))}
      </ul>
    </div>
  );
}

Multiple Queries in a Loader

You can preload multiple queries in a single loader:

import { gql } from "@apollo/client";
import { useReadQuery } from "@apollo/client/react";
import { createFileRoute } from "@tanstack/react-router";

// TypedDocumentNode definitions omitted for brevity

export const Route = createFileRoute("/dashboard")({
  component: RouteComponent,
  loader: ({ context: { preloadQuery } }) => {
    const userQueryRef = preloadQuery(GET_USER, {
      variables: { id: "current" },
    });

    const statsQueryRef = preloadQuery(GET_STATS, {
      variables: { period: "month" },
    });

    return {
      userQueryRef,
      statsQueryRef,
    };
  },
});

function RouteComponent() {
  const { userQueryRef, statsQueryRef } = Route.useLoaderData();
  const { data: userData } = useReadQuery(userQueryRef);
  const { data: statsData } = useReadQuery(statsQueryRef);

  return (
    <div>
      <h1>Welcome, {userData.user.name}</h1>
      <div>
        <h2>Monthly Stats</h2>
        <p>Views: {statsData.stats.views}</p>
        <p>Clicks: {statsData.stats.clicks}</p>
      </div>
    </div>
  );
}

Using useQueryRefHandlers for Refetching

When using useReadQuery, you can get refetch functionality from useQueryRefHandlers:

Important: Always call useQueryRefHandlers before useReadQuery. These two hooks interact with the same queryRef, and calling them in the wrong order could cause subtle bugs.

import { useReadQuery, useQueryRefHandlers, QueryRef } from "@apollo/client/react";

function UserComponent({ queryRef }: { queryRef: QueryRef<GetUserQuery> }) {
  const { refetch } = useQueryRefHandlers(queryRef);
  const { data } = useReadQuery(queryRef);

  return (
    <div>
      <h1>{data.user.name}</h1>
      <button onClick={() => refetch()}>Refresh</button>
    </div>
  );
}

Important Considerations

  1. Import from Integration Package: Always import ApolloClient and InMemoryCache from @apollo/client-integration-tanstack-start, not from @apollo/client, to ensure proper SSR hydration.

  2. Context Type: Use createRootRouteWithContext<ApolloClientIntegration.RouterContext>() to provide proper TypeScript types for the preloadQuery function in loaders.

  3. Loader vs Component Queries:

    • Use preloadQuery in loaders when you want to start fetching data before the component renders
    • Use useSuspenseQuery directly in components for simpler cases or when data fetching can wait until render
  4. Streaming SSR: The integration fully supports React's streaming SSR capabilities. Place Suspense boundaries strategically for optimal user experience.

  5. Cache Management: The Apollo Client instance is shared across all routes, so cache updates from one route will be reflected in all routes that use the same data.

  6. Authentication: Use Apollo Client's SetContextLink for dynamic auth tokens.

Advanced Configuration

Adding Authentication

For authentication in TanStack Start with SSR support, you need to handle both server and client environments differently. Use createIsomorphicFn to provide environment-specific implementations:

import {
  ApolloClient,
  InMemoryCache,
  routerWithApolloClient,
} from "@apollo/client-integration-tanstack-start";
import { ApolloLink, HttpLink } from "@apollo/client";
import { SetContextLink } from "@apollo/client/link/context";
import { createIsomorphicFn } from "@tanstack/react-start";
import { createRouter } from "@tanstack/react-router";
import { getSession, getCookie } from "@tanstack/react-start/server";
import { routeTree } from "./routeTree.gen";

// Create isomorphic link that uses different implementations per environment
const createAuthLink = createIsomorphicFn()
  .server(() => {
    // Server-only: Can access server-side functions like `getCookies`, `getCookie`, `getSession`, etc. exported from `"@tanstack/react-start/server"`
    return new SetContextLink(async (prevContext) => {
      return {
        headers: {
          ...prevContext.headers,
          authorization: getCookie("Authorization"),
        },
      };
    });
  })
  .client(() => {
    // Client-only: Can access `localStorage` or other browser APIs
    return new SetContextLink((prevContext) => {
      return {
        headers: {
          ...prevContext.headers,
          authorization: localStorage.getItem("authToken") ?? "",
        },
      };
    });
  });

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

  const apolloClient = new ApolloClient({
    cache: new InMemoryCache(),
    link: ApolloLink.from([createAuthLink(), httpLink]),
  });

  const router = createRouter({
    routeTree,
    context: {
      ...routerWithApolloClient.defaultContext,
    },
  });

  return routerWithApolloClient(router, apolloClient);
}

Important: The getRouter function is called both on the server and client, so it must not contain environment-specific code. Use createIsomorphicFn to provide different implementations:

  • Server: Can access server-only functions like getSession, getCookies, getCookie from @tanstack/react-start/server to access authentication information in request or session data
  • Client: Can use localStorage or other browser APIs to access auth tokens (if setting credentials: "include" is sufficient, try to prefer that over manually setting auth headers client-side)

This ensures your authentication works correctly in both SSR and browser contexts.

Custom Cache Configuration

import {
  ApolloClient,
  InMemoryCache,
} from "@apollo/client-integration-tanstack-start";
import { HttpLink } from "@apollo/client";
import { createRouter } from "@tanstack/react-router";
import { routeTree } from "./routeTree.gen";
import { routerWithApolloClient } from "@apollo/client-integration-tanstack-start";

export function getRouter() {
  const apolloClient = new ApolloClient({
    cache: new InMemoryCache({
      typePolicies: {
        Query: {
          fields: {
            posts: {
              merge(existing = [], incoming) {
                return [...existing, ...incoming];
              },
            },
          },
        },
      },
    }),
    link: new HttpLink({ uri: "https://your-graphql-endpoint.com/graphql" }),
  });

  const router = createRouter({
    routeTree,
    context: {
      ...routerWithApolloClient.defaultContext,
    },
  });

  return routerWithApolloClient(router, apolloClient);
}

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.