DEV Community

Cover image for Why Your React App Feels Slow (Hint: It’s Your Apollo Cache Strategy)
Werliton Silva
Werliton Silva

Posted on

Why Your React App Feels Slow (Hint: It’s Your Apollo Cache Strategy)

Hey dev! If you’ve ever felt the frustration of watching a component "flicker" white or take precious seconds to load info the user has already seen, you know that state management is no joke.

slow

Imagine you're building a financial dashboard. The user clicks on their profile, goes back home, checks settings... If every single click triggers a full request to the server, you're not just burning processing power - you're delivering a clunky experience. This is exactly why Apollo Client wasn't just born as a "fetcher," but as a powerful caching engine.

Today, we’re getting straight to the point: mastering Apollo Fetch Policies so you can decide exactly when to hit the cache and when to knock on the server’s door.


The Heart of Performance: Apollo's Cache

apollo

Apollo Client doesn't just fetch data; it normalizes and stores it. When you run a query, Apollo creates a local map. If you request that same data again, Apollo decides - based on your configuration - whether to go to the network or hand over what it already has instantly.

arch

1. cache-first (The Smart Default)

This is the default policy. Apollo looks at the cache: "Do I have this?" If yes, it returns it and never touches the network. If no, it fetches from the server and saves it for next time.

  • Use Case: Product category lists that rarely change.
  • Practical Example:
// Perfect for a list of tags the user already loaded when opening the app
const { data, loading } = useQuery(GET_CATEGORIES, {
  fetchPolicy: 'cache-first',
});
Enter fullscreen mode Exit fullscreen mode

2. network-only (Maximum Consistency)

Here, the cache is ignored for reading. Apollo always hits the server for the latest version. Note: It still saves the result to the cache for future queries using cache-first.

  • Use Case: Bank balances or real-time transaction statuses.
  • Practical Example:
// Ensures the user sees the updated balance immediately after a transfer
const { data, loading } = useQuery(GET_USER_BALANCE, {
  fetchPolicy: 'network-only',
});
Enter fullscreen mode Exit fullscreen mode

3. cache-only (Offline/Instant Mode)

In this policy, Apollo will never make a network request. If the data isn't in the cache, it returns an error or undefined.

  • Use Case: Secondary components that depend on data already loaded by a "parent" or the Home screen.
  • Practical Example:
// Displaying a username in a sidebar, assuming the login process already loaded this
const { data } = useQuery(GET_USER_BASIC_INFO, {
  fetchPolicy: 'cache-only',
});
Enter fullscreen mode Exit fullscreen mode

4. no-cache (Privacy & Ephemerality)

Similar to network-only, it always goes to the server. The big difference? It doesn't store the result. The data disappears as soon as the component unmounts.

  • Use Case: Sensitive compliance data (GDPR) or temporary logs that shouldn't persist in memory.
  • Practical Example:
// Fetching audit logs that you don't want floating around in browser memory
const { data } = useQuery(GET_SENSITIVE_LOGS, {
  fetchPolicy: 'no-cache',
});
Enter fullscreen mode Exit fullscreen mode

Quick Comparison

Policy Data Source Saves to Cache? Primary Goal
cache-first Cache (or Network if empty) Yes Loading Speed
network-only Always Network Yes Data Consistency
cache-only Always Cache N/A Zero Latency / Offline
no-cache Always Network No Security & Memory Savings

Conclusion

Setting the right fetchPolicy is what separates an amateur React app from a high-performance professional one. There is no single "best" policy - only the right policy for your user's specific flow. Balancing server load with cache speed is the secret to a fluid UX.

Did you find this technical tip helpful? If you want to see how to configure next-fetch-policy to handle background updates while showing cached data, drop a comment below!


Have you ever struggled with "stale data" using the default cache? Let me know how you handled it!

Top comments (0)