This documentation is for a legacy version of Next.js and Supabase (Lite). For the latest version, please visit the Next.js and Supabase V2 documentation

Fetching data from Supabase

Learn how fetch data from your Supabase database in Makerkit and Next.js

When fetching data from the Supabase Postgres Database, we use the Supabase JS client.

To make data-fetching from Supabase more reusable, our convention is to create a custom React hook for each query we make.

For example, let's take a look at the hook to fetch an organization from Supabase.

First, we want to write a query that receives two parameters:

  1. a Supabase client interface
  2. an organization ID
organizations/queries.ts
export function getOrganizationById(
client: Client,
organizationId: number
) {
return client
.from('organizations')
.select(`
id,
name,
logoURL: logo_url
`)
.eq('id', organizationId)
.throwOnError()
.single();
}

It's important that we pass the client as a parameter so that we can use the function in both the browser and the server.

Now, if we want to use a React Hook to fetch the organization from one of our components, we can use the useSWR hook from swr:

import useSupabase from '~/core/hooks/use-supabase';
import { getOrganizationById } from '~/lib/organizations/database/queries';
import useSWR from 'swr';
function useOrganizationQuery(
organizationId: number
) {
const client = useSupabase();
const key = ['organization', organizationId];
return useSWR(key, async () => {
return getOrganizationById(client, organizationId).then(
(result) => result.data
);
});
}
export default useOrganizationQuery;

There are two ways to use this function:

  1. Server: directly, in a server-side function such as: a Route Handler, a Server Action, a Server Component, or a Middleware
  2. Client: indirectly, in a React Hook in a client-side component

Retrieving data in a server-side function

Let's see some scenarios where we can use this function in a server-side.

Route Handler

When you are fetching data from a Route Handler, you can use the getSupabaseRouteHandlerClient function.

pages/api/organizations/[id]/route.ts
import { getOrganizationById } from '~/lib/organizations/database/queries';
import getSupabaseRouteHandlerClient from '~/core/supabase/route-handler-client';
import { NextRequest, NextResponse } from "next/server";
export const GET = async (
req: NextRequest,
{ params }: { params: { id: string } }
) => {
const client = getSupabaseRouteHandlerClient();
const { data } = await getOrganizationById(client, params.id);
return NextResponse.json(data);
};

Server Action

When you are performing mutations using React Server Actions, you can use the getSupabaseServerActionClient function to read data from the Supabase database.

'use server';
import getSupabaseServerActionClient from '~/core/supabase/action-client';
import { getOrganizationById } from '~/lib/organizations/database/queries';
export async function getOrganizationByIdAction(
organizationId: number
) {
const client = getSupabaseServerActionClient();
const { data } = await getOrganizationById(client, organizationId);
return data;
}

Server Component

When you are fetching data from a Server Component, you can use the getSupabaseServerComponentClient function.

import getSupabaseServerComponentClient from '~/core/supabase/server-component-client';
import { getOrganizationById } from '~/lib/organizations/database/queries';
interface Params {
params: {
id: string;
};
}
async function OrganizationPage({ params }: Params) {
const client = getSupabaseServerComponentClient();
const organization = await getOrganizationById(client, params.id);
return <div>{organization.name}</div>;
}

Retrieving data using a React hook

Now that we have a hook to fetch an organization, we can use it in our components to retrieve the data.

import { useOrganizationQuery } from './use-organization-query';
function OrganizationCard({ organizationId }) {
const {
data: organization,
isLoading,
error
} = useOrganizationQuery(organizationId);
/* data is loading */
if (isLoading) {
return <div>Loading...</div>
}
/* request errored */
if (error) {
return <div>Error!</div>
}
/* request successful, we can access "organization" */
return <div>{organization.name}</div>;
}