supabase-js icon indicating copy to clipboard operation
supabase-js copied to clipboard

Next.js Cache (beta)

Open yannxaver opened this issue 1 year ago • 5 comments

Improve documentation

Link

https://supabase.com/docs/reference/javascript/select

Describe the problem

See the release notes here: https://nextjs.org/blog/next-13-2#nextjs-cache

It is not clear how to take advantage of this feature when fetching data with the supabase.js client.

Describe the improvement

Describe how to set the desired cache duration to enable ISR at the component level.

Additional context

None

yannxaver avatar Mar 10 '23 14:03 yannxaver

You can pass a custom fetch function into supabase and it works.

First create a fetch factory function that takes next cache properties as parameters:

// utils/cache.ts

export const createFetch =
  (options: Pick<RequestInit, "next" | "cache">) =>
  (url: RequestInfo | URL, init?: RequestInit) => {
    return fetch(url, {
      ...init,
      ...options,
    });
  };

Then in your RSC:

import { createFetch } from "@/utils/cache";
  
const supabase = createServerComponentClient({ cookies }, {
    options: {
      global: {
        fetch: createFetch({
          cache: "no-store"
        })
      }
    }
});

sannajammeh avatar Jun 06 '23 13:06 sannajammeh

"Good to know: cookies() is a Dynamic Function whose returned values cannot be known ahead of time. Using it in a layout or page will opt a route into dynamic rendering at request time."

Any way we get around this?

Edit: This might be helpful

RyelBanfield avatar Jun 20 '23 18:06 RyelBanfield

"Good to know: cookies() is a Dynamic Function whose returned values cannot be known ahead of time. Using it in a layout or page will opt a route into dynamic rendering at request time."

Any way we get around this?

Edit: This might be helpful

Yes. Just use the regular supabase client. Create a wrapper like above using only Supabase createClient and service key.

The pre-requisite is that you don't use any auth on the server in that case as that requires the page to be SSR/dynamic rendered.

sannajammeh avatar Jun 21 '23 13:06 sannajammeh

Great snippet! Is anyone able to tell me why the first request isn't getting cached? It looks pretty identical to the third one to me. I'm using a regular refresh with F5 in next dev.

Code:

  const supabase = createClient<Database>(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.SUPABASE_SERVICE_KEY!,
    {
      global: {
        fetch: createFetch({
          next: {
            revalidate: 1800,
          },
        }),
      },
    }
  );

  const { count: items } = await supabase
    .from('sheetsItem')
    .select('*', { count: 'estimated', head: true })
    .eq('active', true);

  const { data: itemsMarketplace } = await supabase.rpc('count_distinct_items');

  const { count: spreadsheets } = await supabase
    .from('sheetsSheet')
    .select('*', { count: 'exact', head: true })
    .eq('active', true);

Logs:

GET /search/spreadsheet200 in 9540ms
  │ HEAD https://api.example.com/rest/v1/sheetsItem?select=*&active=eq.true 206 in 6898ms (cache: SKIP)
  │  │  Cache missed reason: (cache-control: no-cache (hard refresh))
  │  │ HEAD https://api.example.com/rest/v1/sheetsSheet?select=*&active=eq.true 200 in 2ms (cache: HIT)
  │  │ POST https://api.example.com/rest/v1/rpc/count_distinct_items 200 in 0ms (cache: HIT)

cachho avatar Jan 26 '24 17:01 cachho

Great snippet! Is anyone able to tell me why the first request isn't getting cached? It looks pretty identical to the third one to me. I'm using a regular refresh with F5 in next dev.

Code:

  const supabase = createClient<Database>(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.SUPABASE_SERVICE_KEY!,
    {
      global: {
        fetch: createFetch({
          next: {
            revalidate: 1800,
          },
        }),
      },
    }
  );

  const { count: items } = await supabase
    .from('sheetsItem')
    .select('*', { count: 'estimated', head: true })
    .eq('active', true);

  const { data: itemsMarketplace } = await supabase.rpc('count_distinct_items');

  const { count: spreadsheets } = await supabase
    .from('sheetsSheet')
    .select('*', { count: 'exact', head: true })
    .eq('active', true);

Logs:

GET /search/spreadsheet200 in 9540ms
  │ HEAD https://api.example.com/rest/v1/sheetsItem?select=*&active=eq.true 206 in 6898ms (cache: SKIP)
  │  │  Cache missed reason: (cache-control: no-cache (hard refresh))
  │  │ HEAD https://api.example.com/rest/v1/sheetsSheet?select=*&active=eq.true 200 in 2ms (cache: HIT)
  │  │ POST https://api.example.com/rest/v1/rpc/count_distinct_items 200 in 0ms (cache: HIT)

Caching works different in Next.js dev-mode and production

sannajammeh avatar Jan 26 '24 18:01 sannajammeh