Introduction

Supabase Cache Helpers

A collection of framework specific Cache utilities for working with Supabase.

This project was initially created as part of the Supabase Launch Week 5 Hackathon and was awarded "Best Overall Project" 🥇. The official submission can be found in hackathon.md (opens in a new tab). After using it in production for 6 months, the project was rewritten, and now arrives at a stable v1.

The cache helpers bridge the gap between popular frontend cache management solutions such as SWR (opens in a new tab) or React Query (opens in a new tab), and the Supabase client libraries. All features of postgrest-js (opens in a new tab), storage-js (opens in a new tab) and realtime-js (opens in a new tab) are supported. The cache helpers parse any query into a unique and definite query key, and automatically populates your query cache with every mutation using implicit knowledge of the schema. Check out the demo (opens in a new tab) and find out how it feels like for your users.

With Supabase Cache Helpers, you will never define cache keys or implement manual cache updates again. Your UI will be always fast and reactive, and your code clean.

Features

With just one single line of code, you can simplify the logic of fetching, subscribing to updates, and mutating data as well as storage objects in your project, and have all the amazing features of SWR (opens in a new tab) or React Query (opens in a new tab) out-of-the-box.

  • Seamless integration with SWR (opens in a new tab) and React Query (opens in a new tab)
  • Automatic cache key generation
  • Easy Pagination and Infinite Scroll queries
  • Insert, update, upsert and delete mutations
  • Auto-populate cache after mutations and subscriptions
  • Auto-expand mutation queries based on existing cache data to keep app up-to-date
  • One-liner to upload, download and remove Supabase Storage objects

And a lot more.

Motivation

To maximize your velocity, you should always try to minimize the surface area of the tech. In other words, write as little code as possible.[1] (opens in a new tab) As apps grow, queries become more complex. At one point, you will find yourselve writing a lot of repetitive code to query data, define cache keys and update the cache after mutations. Imagine a Master-Detail view. When using SWR, you will probably end up with something like this

const { data: posts, error } = useSWR("posts", () => {
  const { data: posts, error } = await supabase.from("posts").select("*");
 
  if (error) throw error.message;
  return posts;
});

Now you add filters...

const { data: posts, error } = useSWR("posts?is_published=true", () => {
  const { data: posts, error } = await supabase
    .from("posts")
    .select("*")
    .eq("is_published", true);
 
  if (error) throw error.message;
  return posts;
});

You can see how this becomes very cumbersome over time. It is even more fun if you want to mutate the data, e.g. insert a new post without waiting for SWR to revalidate. To make it a smooth experience for the user, the new post should appear in the list(s) instantly, and not only after a revalidation. This can be implemented by mutating the respective cache keys. But how to know what cache keys should be mutated? One would have to decode the keys and check if the table as well as the applied filters match. Imagine doing that for large queries with a lot of filters. Not fun. But what if we could implement a generalizable solution?

Community

GitHub stars (opens in a new tab)

Supabase Cache Helpers is created by psteinroe (opens in a new tab). Follow @psteinroe (opens in a new tab) on Twitter for future project updates.

Feel free to report issues on GitHub (opens in a new tab)!