Automatically revalidate KV Store cache on change with Database Webhooks in Supabase

Jon Meyers
InstructorJon Meyers
Share this video with your friends

Social Share Links

Send Tweet

Supabase Function Hooks allow us to subscribe to change events in the database - such as insert, update and delete - and make a HTTP request with the changed data.

In this lesson, we refactor our revalidate route to handle inserts, updates and deletes.

Additionally, we create a Function Hook to subscribe to all change events on the articles table, and automatically send a POST request to the revalidate route of our Cloudflare Worker.

This automatically refreshes the KV store anytime a value is changed in the database, and decouples the revalidation of our cache, from our user requesting data. This means, theoretically, users should never have to wait for a request to the Supabase origin server, as the cache is automatically populated, updated and cleared to remain in sync with the database.

Code Snippets

Update Revalidate route to handle insert, update and delete

router.post(
  "/revalidate",
  withContent,
  async (request, { SUPABASE_URL, SUPABASE_ANON_KEY, ARTICLES }) => {
    const { type, record, old_record } = request.content;
    const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);

    if (type === "INSERT" || type === "UPDATE") {
      await writeTo(ARTICLES, `/articles/${record.id}`, record);
    }

    if (type === "DELETE") {
      await ARTICLES.delete(`/articles/${old_record.id}`);
    }

    const { data: articles } = await supabase.from("articles").select("*");
    await writeTo(ARTICLES, "/articles", articles);

    return json({ received: true });
  }
);

Run wrangler development server

npx wrangler dev

Publish Cloudflare Worker with Wrangler CLI

npx wrangler publish

Resources

Instructor: [0:00] Currently, our page is showing cached data, if it's available. If the data in the database changes like "Our cool second blog" becomes "Our very cool second blog." [0:09] Then, the only way to update our cache and display that new title is to send a post request to our revalidate route, passing through the ID for the article that we would like to update with fresh data from Supabase.

[0:22] If we send this request and refresh the browser, we'll see our title has updated, but wouldn't it be great if we could subscribe to any changes that happen in our Supabase database and automatically call this revalidate endpoint telling it what had changed.

[0:36] We can do exactly that with database webhooks. From the Supabase dashboard, we want to go to database and then database webhooks. We then want to create a new webhook.

[0:47] Now, you may need to click and enable webhooks button before you see this dialogue. Now, for the name of our webhook, we're going to call it revalidate_cache. We then tell it which table we would like to subscribe to changes on.

[0:59] In our case, articles, and which events we care about. We want to know about inserts, updates, and deletes, as we will need to modify our cache for all of these.

[1:07] The type of hook is going to be HTTP request, the type of method that we want to send for our request is going to be post. We then need the URL for our hosted revalidate endpoint.

[1:19] We can get that by publishing a new version of our Cloudflare worker by saying npx wrangler publish. This will print out our hosted URL here, and we just need to prepend to this with https:// and then paste in our URL.

[1:36] Lastly, we append our revalidate path and click confirm. Now, back over in our revalidate route, rather than just being passed an ID when our webhook calls our revalidate route, we're actually going to get the type.

[1:50] Whether this is an insert update or delete action, and then the new record, if this is an insert or update or the old record, if this is a delete action.

[2:00] Since we have this full record, we don't actually need to go and select anything from Supabase. We can just check if the type is insert or the type is update.

[2:11] Then, we want to update the cache by calling right to, passing it the articles cache, and then the path for our article, which will be /articles/record.id, which is the record coming in from our request.

[2:24] Then, we also want to pass in that record as the data that we want to write to the cache. Now, if the type is delete and we want to await a call to our cache, asking it to delete the value at the path /articles/old_record.id.

[2:40] This is the old record that has been deleted from our Supabase database. Now, we can save this file and deploy a new version of our Cloudflare worker by typing npx wrangler publish.

[2:52] This will print out our production URL, which we can copy from here and paste in our browser along with our /articles endpoint. We can now see each of our three articles.

[3:02] However, if we decide it's time to actually publish our very cool second blog, we can come across to Supabase, find our very cool second blog, and toggle out "is published column" from false to true.

[3:12] Now, if we navigate back to our Cloudflare worker and refresh, we should see our very cool second blog is now published. If we navigate to that particular article, we'll see that its data has also been automatically revalidated using Supabase function hooks.