Search code examples
typescriptnext.jsserver-side-renderingapollo

GraphQL Apollo Client refusing to not use cache in Next.js


Apollo Client is refusing in any circumstances to update cached data with the ones from the server. We are running Apollo Client in Next.js (14.2.5) SSR using the getClient() method below:

import { HttpLink } from "@apollo/client";
import {
  registerApolloClient,
  ApolloClient,
  InMemoryCache,
} from "@apollo/experimental-nextjs-app-support";

export const { getClient } = registerApolloClient(() => {
  return new ApolloClient({
    link: new HttpLink({
      uri: `${process.env.NEXT_PUBLIC_ADMIN_BASE_URI}/api/graphql`,
    }),
    defaultOptions: {
      query: {
        fetchPolicy: "network-only",
      },
    },
    ssrMode: true,
    ssrForceFetchDelay: 1,
    cache: new InMemoryCache({
      resultCaching: false,
      typePolicies: {
        Yachts: {
          merge: true,
          fields: {
            keyFeatures: {
              merge(existing = [], incoming: any[], { readField }) {
                const merged: any[] = existing ? existing.slice(0) : [];
                const featureNameToIndex: Record<string, number> = {};

                // Populate merged array and map from existing features
                existing.forEach((feature: any, index: any) => {
                  const name = readField<string>("name", feature);
                  if (name) {
                    featureNameToIndex[name] = index;
                  }
                });

                // Merge or add incoming features
                incoming.forEach((feature) => {
                  const name = readField<string>("name", feature);
                  if (name) {
                    const index = featureNameToIndex[name];
                    if (typeof index === "number") {
                      // Merge existing and incoming feature data
                      merged[index] = {
                        ...merged[index],
                        ...feature,
                      };
                    } else {
                      // Add new feature
                      featureNameToIndex[name] = merged.length;
                      merged.push(feature);
                    }
                  }
                });

                return merged;
              },
            },
          },
        },
      },
    }),
    /*defaultOptions: {
      watchQuery: {
        fetchPolicy: "no-cache",
        errorPolicy: "ignore",
      },
      query: {
        fetchPolicy: "no-cache",
        errorPolicy: "all",
      },
      mutate: {
        fetchPolicy: "no-cache",
      },
    },*/
  });
});

However making a query, as for example the one below, to our API (which is updating its data correctly, verified through Postman) will return data which are not up to date:

"use server";

import IBrokerino from "@/types/brokerino";
import { getClient } from "@/apollo";
import { gql } from "@apollo/client";

export const fetchBrokerinos = async (): Promise<IBrokerino[]> => {
  const client = getClient();
  const { data } = await client.query({
    query: gql`
      query Users {
        Users(where: { displayOnWebsite: { equals: true } }) {
          docs {
            name
            picture {
              alt
              sizes {
                fhd {
                  url
                  width
                  height
                }
              }
            }
            phones {
              prefix
              number
            }
            langs
            email
            position
          }
        }
      }
    `,
  });
  return data.Users.docs;
};

We have also tried inserting individual fetch-policy to each query set to no-cache, but nothing changes.

We need to get rid of any caching, since our app needs to make a query on each time the website is loaded with data from the API. We have also tried switching to different clients or disabling caching in Next.js, but nothing's helping.

Here's how we are making the server-side query in the page.tsx:

import Hero from "@/components/company/hero";
import Bar from "@/components/nav/bar";
import dynamic from "next/dynamic";
import { fetchBrokerinos } from "@/actions/brokerino";

const View = dynamic(() => import("@/components/view"));
const Footer = dynamic(() => import("@/components/footer"));
const Story = dynamic(() => import("@/components/company/story"));
const Accordion = dynamic(() => import("@/components/company/accordion"));
const Team = dynamic(() => import("@/components/company/team"));
const Lifestyle = dynamic(() => import("@/components/company/lifestyle"));

const Company = async () => {
  return (
    <main className="w-full flex flex-col justify-start items-center">
      <Bar dynamicColor={-1} />
      <View />
      <Hero />
      <Story />
      <Accordion />
      <Team brokerinos={await fetchBrokerinos()} />
      <Lifestyle />
      <Footer />
    </main>
  );
};

export default Company;

Solution

  • This is not Apollo Client caching your requests, but Next.js caching outgoing fetch calls.

    See the Next.js documentation on fetch caching

    You need to set fetchOptions: { cache: "no-store" } to tell Next.js to stop that. This example from the README of the @apollo/experimental-nextjs-app-support package shows that:

    export const { getClient, query, PreloadQuery } = registerApolloClient(() => {
      return new ApolloClient({
        cache: new InMemoryCache(),
        link: new HttpLink({
          // this needs to be an absolute url, as relative urls cannot be used in SSR
          uri: "http://example.com/api/graphql",
          // you can disable result caching here if you want to
          // (this does not work if you are rendering your page with `export const dynamic = "force-static"`)
          fetchOptions: { cache: "no-store" },
        }),
      });
    });
    

    Please remove those

        ssrMode: true,
        ssrForceFetchDelay: 1,
    

    they don't do anything with streaming SSR. You also don't need resultCaching: false, and probably most of the other options.