Query Supabase Data from Next.js Server Components

Jon Meyers
InstructorJon Meyers
Share this video with your friends

Social Share Links

Send Tweet
Published 10 months ago
Updated 7 months ago

Our Supabase project is a hosted PostgreSQL database. In this lesson, we install the Supabase Auth Helpers and Supabase.js npm packages, and configure environment variables to query data from Supabase:

NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key

These values can be found in your Supabase project's API Settings.

Additionally, we create a new Supabase instance using the createServerComponentClient function, then make our Server Component Async and suspend its rendering until our request for Supabase data resolves.

Lastly, we implement a Row Level Security (RLS) policy to enable read access for the tweets table.

Code Snippets

Install Supabase packages

npm i @supabase/auth-helpers-nextjs @supabase/supabase-js

Import createServerComponentClient function

import { createServerComponentClient } from "@supabase/auth-helpers-nextjs";
import { cookies } from "next/headers";

Create Supabase client in Server Component

const supabase = createServerComponentClient({ cookies });

Fetch data from Supabase

const { data: tweets } = await supabase.from("tweets").select();

Pretty print data with JSON.stringify

<pre>{JSON.stringify(tweets, null, 2)}</pre>

Enable read access with RLS policy

create policy "anyone can select tweets" ON "public"."tweets"
as permissive for select
to public
using (true);

Resources

Instructor: Let's replace the contents of this page with our tweets from Supabase. Back over in VS code, we can quit our development server and then run npm install or i @supabase/auth-helpers-nextjs. This requires the @supabase/supabase-js library.

Then once that's installed, we can run npm run dev to start our development server again. Then we want to create a new file in the root-most directory of our application. This is going to be called .env.local. In here, we want a NEXT_PUBLIC_SUPABASE_URL and also an ANON_KEY.

We can get these from our Supabase dashboard under Settings and then API. The Project URL section will have our URL which we can paste in here. Then under Project API keys, we want this anon public key. We'll copy this here, paste it here.

Then back over in our page.tsx file, we want to create a new supabase instance. We can do this by calling the createServerComponentClient function which comes in from that @supabase/auth-helpers-nextjs package. This function takes in an object which has a cookies function which we can import above from next/headers.

The reason we're specifically creating a server component client here is that, by default, any pages in the app directory are automatically server components. This means, when the browser requests this page, this function runs on the server. It then generates the HTML for the page and sends that back to the browser.

No client-side JavaScript is required to render out this page, so Next.js doesn't send any client-side JavaScript back to the browser. Another cool thing about server components is, they can now be marked as async, which means we can fetch data directly in this server component.

For example, we could get all of our tweets by awaiting a call to supabase, and from the tweets table, selecting all rows. Our route is now going to wait for these tweets to come back from supabase before rendering this HTML.

We don't need to return a loading spinner while we're fetching that data. As soon as we hit this return statement, we've already got our tweets from supabase. We can just render a <pre> tag and use JSON.stringify to pretty-print out our list of tweets.

If we go over to the browser and refresh, we'll see this empty array. If we go over to our Supabase dashboard and look at our tweets table, we can see that we have those three tweets, so why aren't they displaying in our Next.js app?

This is because we enabled row level security or RLS for the tweets table. RLS automatically denies all requests to that table. No one can select, insert, update, or delete any of the rows in this table. If we want to enable one of those actions, we need to write a policy.

There are some templates to help you get started, but we're going to create this one from scratch. Our policy name is going to be, anyone can select tweets. It's going to enable the SELECT action. We're going to leave Target roles as public, and then our USING expression needs to have a condition that either evaluates to true or false.

If it's true, then the select action will be allowed. If it's false, then it will continue to be denied. In this case, we want to use the value true, which means that anyone can select tweets. Let's click Review, which will show the SQL that's been generated for this policy. Then we can click Save policy to run this SQL against our Supabase database.

Now that we've got that SELECT policy, if we go back to our application and refresh, we'll see our list of tweets are being sent back by Supabase and successfully rendered by our Next.js server component.

Xuefeng Wu
Xuefeng Wu
~ 10 months ago

Hi, the <pre> element should be nested inside a <div> element, otherwise hydration error occurs. And another thing is I need to run 'npm add -D encoding', otherwise I got warn in my console.

Markdown supported.
Become a member to join the discussionEnroll Today