Skip to content
Development
Skill

/web-data-fetching-graphql-apollo

Apollo Client GraphQL patterns — normalized cache and type policies, queries, mutations with optimistic updates, pagination, fragments, subscriptions, and Suspense hooks

From plugin
agents-inc-skills
24200 skills
Install
$ npx -y skills add agents-inc/skills --skill web-data-fetching-graphql-apollo --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/web-data-fetching-graphql-apollo

Context preview

The summary Claude sees to decide when to auto-load this skill.

Apollo Client GraphQL patterns — normalized cache and type policies, queries, mutations with optimistic updates, pagination, fragments, subscriptions, and Suspense hooks

SKILL.md

web-data-fetching-graphql-apollo.SKILL.md
name: web-data-fetching-graphql-apollo
description: Apollo Client GraphQL patterns — normalized cache and type policies, queries, mutations with optimistic updates, pagination, fragments, subscriptions, and Suspense hooks

Apollo Client Patterns

> **Quick Guide:** Apollo stores every entity once, keyed by `__typename` plus its `keyFields`, and > re-renders everything watching it. Most of the difficulty is in the cache rather than the hooks: > `keyFields` decides identity, `keyArgs` decides how many cache entries a paginated field gets, and > an optimistic response missing `__typename` fails to normalize without saying so. v3.9 added the > Suspense hooks; v4 moved the React hooks to `@apollo/client/react` and typed the error classes.

**Detailed Resources:**

  • [examples/core.md](examples/core.md) — codegen config, client and link chain, `useQuery`, `useLazyQuery`, mutations with cache updates
  • [examples/pagination.md](examples/pagination.md) — `fetchMore` with an observer, relay and offset type policies
  • [examples/fragments.md](examples/fragments.md) — fragment definition, composition and use in queries
  • [examples/error-handling.md](examples/error-handling.md) — partial data rendering, global error link
  • [examples/subscriptions.md](examples/subscriptions.md) — split link over `graphql-ws`, `useSubscription` writing to cache
  • [examples/suspense.md](examples/suspense.md) — `useSuspenseQuery`, `useLoadableQuery`, `useBackgroundQuery`, `createQueryPreloader`
  • [examples/testing.md](examples/testing.md) — `MockedProvider`, mock shapes, asserting cache updates, schema-based testing
  • [reference.md](reference.md) — fetch/error policy, network status and cache method tables, v3 → v4 migration

---

Which path applies

  • **Apollo Client v4** — React hooks come from `@apollo/client/react`, links are constructed with

`new HttpLink()`, `uri` on the client is gone, and errors are `CombinedGraphQLErrors` / `ServerError` rather than one `ApolloError`. The full map is in [reference.md](reference.md); `npx @apollo/client-codemod-migrate-3-to-4` does the mechanical part.

  • **Suspense loading** — the component suspends instead of returning `loading`, and errors throw to

the nearest error boundary. Pattern 9, then [examples/suspense.md](examples/suspense.md).

  • **Classic hooks** — `useQuery` returns `loading`, `error` and `data`, and the component renders

each state itself. Patterns 2 onward.

---

<critical_requirements>

Before writing Apollo code

**Generate the operation types from the schema.** A hand-written response type is a second copy of the schema that nothing keeps in step, and it goes wrong silently — the field the backend added is absent from the type and absent from every render that needed it.

**Put `__typename` and the identifying field in every optimistic response.** Without them the entry cannot be normalized, so the optimistic write lands nowhere and the UI does not move until the server answers.

**Give every entity type a `keyFields` policy.** It is what decides whether two responses are the same entity, and the default `["id"]` is wrong for anything keyed on `sku`, a slug, or a pair.

</critical_requirements>

---

**Auto-detection:** `ApolloClient`, `InMemoryCache`, `ApolloProvider`, `useQuery`, `useLazyQuery`, `useMutation`, `useSubscription`, `useFragment`, `useSuspenseQuery`, `useLoadableQuery`, `useBackgroundQuery`, `useReadQuery`, `createQueryPreloader`, `typePolicies`, `keyFields`, `keyArgs`, `cache.modify`, `cache.evict`, `relayStylePagination`, `makeVar`, `gql`

**Applies to:**

  • Normalized caching, type policies and cache identity
  • Queries, mutations, optimistic responses and cache updates after a write
  • Cursor and offset pagination through `fetchMore`
  • Fragment colocation and reading a fragment straight from the cache
  • Real-time data over a subscription link
  • Suspense-based loading and route preloading

**Handled elsewhere:**

  • APIs addressed over REST — this client speaks one query language
  • Designing the schema and its resolvers; this skill consumes a schema
  • Client state that does not correspond to any server field — reactive variables cover the simple

cases here, and anything derived or complex belongs to whatever owns client state

  • Form state and validation
  • Where errors are shipped once the error link has caught them

---

<philosophy>

Philosophy

The cache is the product. A response is not stored as a response — it is split into entities keyed by `__typename` plus `keyFields`, and every hook watching one of those entities re-renders when it changes. So one mutation updates every list, detail view and badge showing that entity, without any of them refetching.

The corollary is that everything which can go wrong with Apollo is an identity question: two responses that should have been one entry, one entry that should have been two, or a write the cache could not place because it did not know what it was.

</philosophy>

---

<patterns>

Core patterns

Pattern 1: Client setup and type policies

Build the cache with a type policy per entity, and compose the link chain so auth and error handling sit in front of the transport.

const cache = new InMemoryCache({
  typePolicies: {
    User: { keyFields: ["id"] },
    Product: { keyFields: ["sku"] }, // identity is not always "id"
    CartItem: { keyFields: false }, // embed in the parent, never its own entry
    Query: { fields: { usersConnection: relayStylePagination(["filter"]) } },
  },
});

`keyFields` takes `["id"]`, another single field, a composite like `["authorId", "postId"]`, `[]` for a singleton, or `false` to embed.

Full code: [examples/core.md](examples/core.md) — codegen config, auth link, error link, client singleton

---

Pattern 2: Queries

const { data, loading, error, refetch } = useQuery<GetUsersQuery, GetUsersQueryVariables>(
  GET_USERS,
  { variables: { limit: DEFAULT_PAGE_SIZE }, fetchPolicy: "cache-and-networ
Read more
Ships withagents-inc-skills

The official skills marketplace for Agents Inc. 150+ skills covering everything from React and Prisma to Redis, ElevenLabs, and infrastructure tooling. Pick the skills that match your stack and install them via Claude Code. Need more control?

Get the whole plugin

Other skills on agents-inc-skills.