Apollo Client for GraphQL: Optimization & Code Generation

As your project grows, the number of GraphQL queries multiplies—and the N+1 problem and cache desync become real headaches. We've seen code where every component fires its own `useQuery`, and on mutation you have to manually reset the cache. In one e-commerce project with 50,000 products, each catal

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1283
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1237
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    980
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    1029
  • image_website-sbh_0.webp
    Website development for SBH Partners
    1104
  • image_website-_0.webp
    Website development for Red Pear
    552

As your project grows, the number of GraphQL queries multiplies—and the N+1 problem and cache desync become real headaches. We've seen code where every component fires its own useQuery, and on mutation you have to manually reset the cache. In one e-commerce project with 50,000 products, each catalog component executed its own useQuery, causing N+1 and slowdowns. After configuring Apollo Client with InMemoryCache, API load dropped by 40%.

Apollo Client with normalized InMemoryCache solves this: it automatically updates all components subscribed to changed entities. Over 5 years, we've implemented it on 15+ projects—from online stores to real-time dashboards. According to Apollo Client documentation, using a normalized cache reduces manual updates by 30%.

Below is a concrete setup guide: from client configuration to code generation and cache optimization. No fluff—only working configs and patterns.

Why Apollo Client over urql for complex projects?

Criterion Apollo Client urql Relay
Normalized cache Yes, InMemoryCache Yes, document cache Yes
Subscriptions Yes Yes Via subscriptions-transport-ws
Size (min+gzip) ~34 KB ~15 KB ~45 KB
Popularity (npm/week) 2.5M+ 500K+ 400K+
React integration Hooks + HOC Hooks Fragment model

Apollo Client is 5× more popular than urql by npm downloads and provides a more mature toolbox. For products with dozens of interconnections, a normalized cache is a critical advantage: it saves up to 30% development time because you don't have to write manual updates. Additionally, Apollo automatically deduplicates identical queries, reducing server load in high-traffic apps—urql lacks this feature.

How to properly configure Apollo Client?

Installation and client configuration

Install packages and create a client with HTTP and WebSocket links, authentication, and error handling. The key element is InMemoryCache with typePolicies for pagination:

import { ApolloClient, InMemoryCache, createHttpLink, from, split, ApolloLink } from '@apollo/client' import { setContext } from '@apollo/client/link/context' import { onError } from '@apollo/client/link/error' import { GraphQLWsLink } from '@apollo/client/link/subscriptions' import { createClient as createWsClient } from 'graphql-ws' import { getMainDefinition } from '@apollo/client/utilities' const httpLink = createHttpLink({ uri: import.meta.env.VITE_GRAPHQL_URL ?? '/graphql' }) const authLink = setContext((_, { headers }) => { const token = localStorage.getItem('token') return { headers: { ...headers, ...(token ? { authorization: `Bearer ${token}` } : {}) } } }) const errorLink = onError(({ graphQLErrors, networkError }) => { graphQLErrors?.forEach(({ message, extensions }) => { if (extensions?.code === 'UNAUTHENTICATED') { /* logout */ } }) }) const wsLink = new GraphQLWsLink(createWsClient({ url: import.meta.env.VITE_GRAPHQL_WS_URL, connectionParams: { authorization: `Bearer ${localStorage.getItem('token')}` } })) const splitLink = split( ({ query }) => getMainDefinition(query).operation === 'subscription', wsLink, from([errorLink, authLink, httpLink]) ) export const client = new ApolloClient({ link: splitLink, cache: new InMemoryCache({ typePolicies: { Query: { fields: { products: { keyArgs: ['categoryId'], merge(existing, incoming, { args }) { return args?.offset ? { ...incoming, items: [...(existing?.items ?? []), ...incoming.items] } : incoming } } } } } }), defaultOptions: { watchQuery: { fetchPolicy: 'cache-and-network', errorPolicy: 'all' }, query: { fetchPolicy: 'network-only', errorPolicy: 'all' } } }) 

Fragment matcher for interface fragments

If your schema uses interfaces or union types, configure IntrospectionFragmentMatcher or possibleTypes in the cache. Otherwise Apollo won't normalize fragments, and the cache will reset on every request. Generate possibleTypes automatically with @graphql-codegen/fragment-matcher.

Optimistic updates

Apollo Client supports optimistic updates: you can instantly update the UI while the server request is in flight. Configure the update function in useMutation and pass optimisticResponse. This reduces perceived latency and improves UX.

How to speed up development with code generation?

Code generation of types from the GraphQL schema saves up to 30% of time writing TypeScript interfaces. Configure @graphql-codegen:

npm install -D @graphql-codegen/cli @graphql-codegen/client-preset npx graphql-codegen init 

In codegen.ts specify schema and documents, enable strictScalars:

import type { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { overwrite: true, schema: 'http://localhost:4000/graphql', documents: 'src/**/*.graphql', generates: { 'src/gql/': { preset: 'client', config: { useTypeImports: true, strictScalars: true, scalars: { DateTime: 'string', UUID: 'string' } } } } } export default config 

Run npx graphql-codegen --watch in development and npx graphql-codegen in CI.

Common mistakes when configuring Apollo Client

The most frequent one is incorrect typePolicies setup. If you don't set keyArgs for pagination fields, the cache will mix data from different pages. The second mistake is ignoring errorPolicy: 'all' when handling partial errors. The third is forgetting to pass connectionParams for WebSocket authentication, causing subscriptions to fail with 401.

How to debug cache issues in Apollo Client?

Use Apollo DevTools: the Chrome/Firefox extension visualizes the cache, query history, and mutations. It lets you execute arbitrary GraphQL queries directly from the browser. DevTools cuts debugging time by 40%.

Working with queries, mutations, and subscriptions

After code generation, use generated types and hooks. Example documents and hooks:

query GetProducts($categoryId: ID!, $offset: Int, $limit: Int) { products(categoryId: $categoryId, offset: $offset, limit: $limit) { items { id name price stock } total hasMore } } 
import { useQuery } from '@apollo/client' import { GetProductsDocument } from '@/gql/graphql' export function useProducts(categoryId: string) { return useQuery(GetProductsDocument, { variables: { categoryId }, notifyOnNetworkStatusChange: true }) } 

What's included in the work?

  • Analysis of existing GraphQL schema and documents
  • Client configuration with HTTP/WS links, authentication, error handling
  • InMemoryCache setup with typePolicies for your entities
  • Code generation of TypeScript types and hooks (CI integration)
  • Subscription and authentication integration
  • Testing and debugging with Apollo DevTools
  • Usage and maintenance documentation

Process and timeline

Stage Duration
Schema and document analysis 0.5 day
Client and cache configuration 1 day
Code generation and hooks 1 day
Subscription and auth integration 0.5 day
Testing and debugging 1 day
Documentation 0.5 day

Cost is calculated individually based on schema complexity and scope. Estimated timeline: from 3 to 5 days.

We guarantee: compatibility with any React stack, support for the latest @apollo/client versions, detailed documentation. Our experience: 15+ projects on Apollo Client, including high-load e-commerce. Get a consultation—we'll evaluate your project in 1 day. Order Apollo Client setup for your project—we'll contact you within an hour.