{"id":"c3f87cd3-8069-45ab-a8ba-9165ca42c382","shortId":"x3qLgf","kind":"skill","title":"Apollo Client","tagline":"Skills skill by Apollographql","description":"# Apollo Client 4.x Guide\n\nApollo Client is a comprehensive state management library for JavaScript that enables you to manage both local and remote data with GraphQL. Version 4.x brings improved caching, better TypeScript support, and React 19 compatibility.\n\n## Integration Guides\n\nChoose the integration guide that matches your application setup:\n\n- **[Client-Side Apps](references/integration-client.md)** - For client-side React applications without SSR (Vite, Create React App, etc.)\n- **[Next.js App Router](references/integration-nextjs.md)** - For Next.js applications using the App Router with React Server Components\n- **[React Router Framework Mode](references/integration-react-router.md)** - For React Router 7 applications with streaming SSR\n- **[TanStack Start](references/integration-tanstack-start.md)** - For TanStack Start applications with modern routing\n\nEach guide includes installation steps, configuration, and framework-specific patterns optimized for that environment.\n\n## Quick Reference\n\n### Basic Query\n\n```tsx\nimport { gql } from \"@apollo/client\";\nimport { useQuery } from \"@apollo/client/react\";\n\nconst GET_USER = gql`\n  query GetUser($id: ID!) {\n    user(id: $id) {\n      id\n      name\n    }\n  }\n`;\n\nfunction UserProfile({ userId }: { userId: string }) {\n  const { loading, error, data, dataState } = useQuery(GET_USER, {\n    variables: { id: userId },\n  });\n\n  if (loading) return <p>Loading...</p>;\n  if (error) return <p>Error: {error.message}</p>;\n\n  // TypeScript: dataState === \"ready\" provides better type narrowing than just checking data\n  return <div>{data.user.name}</div>;\n}\n```\n\n### Basic Mutation\n\n```tsx\nimport { gql } from \"@apollo/client\";\nimport { useMutation } from \"@apollo/client/react\";\n\nconst CREATE_USER = gql`\n  mutation CreateUser($input: CreateUserInput!) {\n    createUser(input: $input) {\n      id\n      name\n    }\n  }\n`;\n\nfunction CreateUserForm() {\n  const [createUser, { loading, error }] = useMutation(CREATE_USER);\n\n  const handleSubmit = async (name: string) => {\n    await createUser({ variables: { input: { name } } });\n  };\n\n  return <button onClick={() => handleSubmit(\"John\")}>Create User</button>;\n}\n```\n\n### Suspense Query\n\n```tsx\nimport { Suspense } from \"react\";\nimport { useSuspenseQuery } from \"@apollo/client/react\";\n\nfunction UserProfile({ userId }: { userId: string }) {\n  const { data } = useSuspenseQuery(GET_USER, {\n    variables: { id: userId },\n  });\n\n  return <div>{data.user.name}</div>;\n}\n\nfunction App() {\n  return (\n    <Suspense fallback={<p>Loading user...</p>}>\n      <UserProfile userId=\"1\" />\n    </Suspense>\n  );\n}\n```\n\n## Reference Files\n\nDetailed documentation for specific topics:\n\n- [TypeScript Code Generation](references/typescript-codegen.md) - GraphQL Code Generator setup for type-safe operations\n- [Queries](references/queries.md) - useQuery, useLazyQuery, polling, refetching\n- [Suspense Hooks](references/suspense-hooks.md) - useSuspenseQuery, useBackgroundQuery, useReadQuery, useLoadableQuery\n- [Mutations](references/mutations.md) - useMutation, optimistic UI, cache updates\n- [Fragments](references/fragments.md) - Fragment colocation, useFragment, useSuspenseFragment, data masking\n- [Caching](references/caching.md) - InMemoryCache, typePolicies, cache manipulation\n- [State Management](references/state-management.md) - Reactive variables, local state\n- [Error Handling](references/error-handling.md) - Error policies, error links, retries\n- [Troubleshooting](references/troubleshooting.md) - Common issues and solutions\n\n## Key Rules\n\n### Query Best Practices\n\n- **Each page should generally only have one query, composed from colocated fragments.** Use `useFragment` or `useSuspenseFragment` in all non-page-components. Use `@defer` to allow slow fields below the fold to stream in later and avoid blocking the page load.\n- **Fragments are for colocation, not reuse.** Each fragment should describe exactly the data needs of a specific component, not be shared across components for common fields. See [Fragments reference](references/fragments.md) for details on fragment colocation and data masking.\n- Always handle `loading` and `error` states in UI when using non-suspenseful hooks (`useQuery`, `useLazyQuery`). When using Suspense hooks (`useSuspenseQuery`, `useBackgroundQuery`), React handles this through `<Suspense>` boundaries and error boundaries.\n- Use `fetchPolicy` to control cache behavior per query\n- Use the TypeScript type server to look up documentation for functions and options (Apollo Client has extensive docblocks)\n\n### Mutation Best Practices\n\n- **If the schema permits, mutation return values should return everything necessary to update the cache.** Neither manual updates nor refetching should be necessary.\n- If the mutation response is insufficient, carefully weigh manual cache manipulation vs refetching. Manual updates risk missing server logic. Consider optimistic updates with a granular refetch if needed.\n- Handle errors gracefully in the UI\n- Use `refetchQueries` sparingly (prefer letting the cache update automatically)\n\n### Caching Best Practices\n\n- Configure `keyFields` for types without `id` field\n- Disable normalization by setting `keyFields: false` for types that don't include an identifier and are meant to group related fields under the parent\n- Use `typePolicies` for pagination and computed fields\n- Understand cache normalization to debug issues\n- **Enable [data masking](references/fragments.md#data-masking) for all new applications** - it prevents components from accessing fragment data they don't own, enforcing proper data boundaries and preventing over-rendering\n\n### Performance\n\n- Avoid over-fetching with proper field selection\n- Configure appropriate `fetchPolicy` per use case\n- Use `@defer` for incremental delivery of deferred query parts, and `@stream` for streaming list fields (`@stream` available in Apollo Client 4.1+)\n- **Prefer Suspense hooks (`useSuspenseQuery`, `useBackgroundQuery`) in modern applications** for better loading state handling and code simplicity\n\n## Ground Rules\n\n- ALWAYS use Apollo Client 4.x patterns (not v3 or earlier)\n- ALWAYS wrap your app with `ApolloProvider`\n- ALWAYS handle loading and error states when using non-suspenseful hooks\n- PREFER Suspense hooks (`useSuspenseQuery`, `useBackgroundQuery`) in modern applications for better DX\n- NEVER store Apollo Client in React state (use module-level or context)\n- PREFER `cache-first` for read-heavy data, `network-only` for real-time data\n- USE TypeScript for better type safety with GraphQL\n- IMPLEMENT proper cache updates instead of refetching entire queries\n- ADVISE the human steering you to look into Apollo DevTools when collaboratively debugging Apollo Client issues","tags":["apollo","client","skills","apollographql"],"capabilities":["skill","source-apollographql","category-skills"],"categories":["skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/apollographql/skills/apollo-client","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"install_from":"skills.sh"}},"qualityScore":"0.300","qualityRationale":"deterministic score 0.30 from registry signals: · indexed on skills.sh · published under apollographql/skills","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill:v1","enrichmentVersion":1,"enrichedAt":"2026-04-23T15:40:29.716Z","embedding":null,"createdAt":"2026-04-18T20:29:14.643Z","updatedAt":"2026-04-23T15:40:29.716Z","lastSeenAt":"2026-04-23T15:40:29.716Z","tsv":"'19':45 '4':9,35,696 '4.1':673 '7':99 'access':622 'across':418 'advis':779 'allow':381 'alway':435,692,703,709 'apollo':1,7,12,486,671,694,734,787,792 'apollo/client':137,199 'apollo/client/react':141,203,253 'apollographql':6 'apolloprovid':708 'app':61,74,77,85,270,706 'applic':56,68,82,100,110,617,681,728 'appropri':648 'async':228 'automat':559 'avail':669 'avoid':392,639 'await':231 'basic':131,193 'behavior':470 'best':354,492,561 'better':40,184,683,730,765 'block':393 'boundari':461,464,632 'bring':37 'button':237 'cach':39,314,324,328,469,508,526,557,560,602,747,772 'cache-first':746 'care':523 'case':652 'category-skills' 'check':189 'choos':49 'client':2,8,13,59,65,487,672,695,735,793 'client-sid':58,64 'code':284,288,688 'collabor':790 'coloc':319,366,400,431 'common':347,421 'compat':46 'compon':90,377,414,419,620 'compos':364 'comprehens':16 'comput':599 'configur':119,563,647 'consid':536 'const':142,160,204,219,226,259 'context':744 'control':468 'creat':72,205,224,241 'createus':209,212,220,232 'createuserform':218 'createuserinput':211 'data':31,163,190,260,322,409,433,608,612,624,631,753,761 'data-mask':611 'data.user.name':192,268 'datast':164,181 'debug':605,791 'defer':379,654,659 'deliveri':657 'describ':406 'detail':278,428 'devtool':788 'disabl':570 'docblock':490 'document':279,481 'dx':731 'earlier':702 'enabl':23,607 'enforc':629 'entir':777 'environ':128 'error':162,176,178,222,337,340,342,439,463,546,713 'error.message':179 'etc':75 'everyth':503 'exact':407 'extens':489 'fallback':273 'fals':575 'fetch':642 'fetchpolici':466,649 'field':383,422,569,590,600,645,667 'file':277 'first':748 'fold':386 'fragment':316,318,367,397,404,424,430,623 'framework':93,122 'framework-specif':121 'function':155,217,254,269,483 'general':359 'generat':285,289 'get':143,166,262 'getus':147 'gql':135,145,197,207 'grace':547 'granular':541 'graphql':33,287,769 'ground':690 'group':588 'guid':11,48,52,115 'handl':338,436,458,545,686,710 'handlesubmit':227,239 'heavi':752 'hook':303,448,454,676,720,723 'human':781 'id':148,149,151,152,153,169,215,265,568 'identifi':583 'implement':770 'import':134,138,196,200,246,250 'improv':38 'includ':116,581 'increment':656 'inmemorycach':326 'input':210,213,214,234 'instal':117 'instead':774 'insuffici':522 'integr':47,51 'issu':348,606,794 'javascript':21 'john':240 'key':351 'keyfield':564,574 'later':390 'let':555 'level':742 'librari':19 'link':343 'list':666 'load':161,172,174,221,274,396,437,684,711 'local':28,335 'logic':535 'look':479,785 'manag':18,26,331 'manipul':329,527 'manual':510,525,530 'mask':323,434,609,613 'match':54 'meant':586 'miss':533 'mode':94 'modern':112,680,727 'modul':741 'module-level':740 'mutat':194,208,309,491,498,519 'name':154,216,229,235 'narrow':186 'necessari':504,516 'need':410,544 'neither':509 'network':755 'network-on':754 'never':732 'new':616 'next.js':76,81 'non':375,446,718 'non-page-compon':374 'non-suspens':445,717 'normal':571,603 'onclick':238 'one':362 'oper':295 'optim':125 'optimist':312,537 'option':485 'over-fetch':640 'over-rend':635 'page':357,376,395 'pagin':597 'parent':593 'part':661 'pattern':124,698 'per':471,650 'perform':638 'permit':497 'polici':341 'poll':300 'practic':355,493,562 'prefer':554,674,721,745 'prevent':619,634 'proper':630,644,771 'provid':183 'queri':132,146,244,296,353,363,472,660,778 'quick':129 'react':44,67,73,88,91,97,249,457,737 'reactiv':333 'read':751 'read-heavi':750 'readi':182 'real':759 'real-tim':758 'refer':130,276,425 'references/caching.md':325 'references/error-handling.md':339 'references/fragments.md':317,426,610 'references/integration-client.md':62 'references/integration-nextjs.md':79 'references/integration-react-router.md':95 'references/integration-tanstack-start.md':106 'references/mutations.md':310 'references/queries.md':297 'references/state-management.md':332 'references/suspense-hooks.md':304 'references/troubleshooting.md':346 'references/typescript-codegen.md':286 'refetch':301,513,529,542,776 'refetchqueri':552 'relat':589 'remot':30 'render':637 'respons':520 'retri':344 'return':173,177,191,236,267,271,499,502 'reus':402 'risk':532 'rout':113 'router':78,86,92,98 'rule':352,691 'safe':294 'safeti':767 'schema':496 'see':423 'select':646 'server':89,477,534 'set':573 'setup':57,290 'share':417 'side':60,66 'simplic':689 'skill':3,4 'slow':382 'solut':350 'source-apollographql' 'spare':553 'specif':123,281,413 'ssr':70,103 'start':105,109 'state':17,330,336,440,685,714,738 'steer':782 'step':118 'store':733 'stream':102,388,663,665,668 'string':159,230,258 'support':42 'suspens':243,247,272,302,447,453,675,719,722 'tanstack':104,108 'time':760 'topic':282 'troubleshoot':345 'tsx':133,195,245 'type':185,293,476,566,577,766 'type-saf':292 'typepolici':327,595 'typescript':41,180,283,475,763 'ui':313,442,550 'understand':601 'updat':315,506,511,531,538,558,773 'use':83,368,378,444,452,465,473,551,594,651,653,693,716,739,762 'usebackgroundqueri':306,456,678,725 'usefrag':320,369 'uselazyqueri':299,450 'useloadablequeri':308 'usemut':201,223,311 'usequeri':139,165,298,449 'user':144,150,167,206,225,242,263,275 'usereadqueri':307 'userid':157,158,170,256,257,266 'userprofil':156,255 'usesuspensefrag':321,371 'usesuspensequeri':251,261,305,455,677,724 'v3':700 'valu':500 'variabl':168,233,264,334 'version':34 'vite':71 'vs':528 'weigh':524 'without':69,567 'wrap':704 'x':10,36,697","prices":[{"id":"6439b072-c911-41c8-8fba-7fa1e44bd25d","listingId":"c3f87cd3-8069-45ab-a8ba-9165ca42c382","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"apollographql","category":"skills","install_from":"skills.sh"},"createdAt":"2026-04-18T20:29:14.643Z"}],"sources":[{"listingId":"c3f87cd3-8069-45ab-a8ba-9165ca42c382","source":"github","sourceId":"apollographql/skills/apollo-client","sourceUrl":"https://github.com/apollographql/skills/tree/main/skills/apollo-client","isPrimary":false,"firstSeenAt":"2026-04-18T22:17:20.181Z","lastSeenAt":"2026-04-23T12:56:09.139Z"},{"listingId":"c3f87cd3-8069-45ab-a8ba-9165ca42c382","source":"skills_sh","sourceId":"apollographql/skills/apollo-client","sourceUrl":"https://skills.sh/apollographql/skills/apollo-client","isPrimary":true,"firstSeenAt":"2026-04-18T20:29:14.643Z","lastSeenAt":"2026-04-23T15:40:29.716Z"}],"details":{"listingId":"c3f87cd3-8069-45ab-a8ba-9165ca42c382","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"apollographql","slug":"apollo-client","source":"skills_sh","category":"skills","skills_sh_url":"https://skills.sh/apollographql/skills/apollo-client"},"updatedAt":"2026-04-23T15:40:29.716Z"}}