Next.js App router is pretty awesome. Sadly, it’s super new. The errors you face are sometimes hard to debug as you can’t see where it’s coming from and why. I hope they fix it soon.
Supabase is pretty awesome, too. I’ve been using it as a backend, database, file storage, and, most importantly, as an authentication service for one of my production Next.js app router-based apps.
Invariant: cookies() expects to have requestAsyncStorage, none available#
It’s all good and well on the localhost, but when you try to deploy it, most of us face the dreaded Invariant: cookies() expects to have requestAsyncStorage, none available
error. There are a lot of ideas on this GitHub issue, but sadly none worked.
Fix: The async function: cookies() expects requestAsyncStorage, none available#
And then I went down the rabbit hole with console logging everything to figure out that well cookies probably need to be awaited since the React Server Components are async
functions.
Lo and behold, that was it. Making it an async call fixed it for me.
Now I have a file called lib/supabase.ts
which looks like this:
import {
createClientComponentClient,
createRouteHandlerClient,
createServerActionClient,
createServerComponentClient,
} from '@supabase/auth-helpers-nextjs';
import { cookies } from 'next/headers';
import { cache } from 'react';
import 'server-only';
export const dynamic = 'force-dynamic';
export const getDbOnSever = cache(async () => {
const cookieStore = cookies();
return createServerComponentClient<Database>({ cookies: () => cookieStore });
});
export const getDbOnAction = cache(async () => {
const cookieStore = cookies();
return createServerActionClient<Database>({ cookies: () => cookieStore });
});
export const getDbOnRoute = cache(async () => {
const cookieStore = cookies();
return createRouteHandlerClient<Database>({ cookies: () => cookieStore });
});
Note the async
nature of all the functions. I know nothing is awaited but the function now returns a promise and can be awaited in a server component, route, or an action. And that way, we get the cookies.
Usage#
You can use these functions in your React server components, actions, and API routes. Like this:
// React Server Component.
import { getDbOnSever } from '@/lib/db-server';
import { cache } from 'react';
export const dynamic = 'force-dynamic';
export default async function Page() {
const getApps = cache(async () => {
const supabase = await getDbOnSever();
const { data: apps, error } = await supabase.from('apps').select();
return apps;
});
const apps = await getApps();
<pre>{JSON.stringify(apps, null, 2)}</pre>;
}
Conditions#
- Async/Await: React Server Component, Server Action, or API Route should all be
async
functions where you await
the db client as shown above.
- Dynamic it is: Remember to use
export const dynamic = 'force-dynamic';
as recommended by Supabase. Read more about it on docs.
That’s it and that’s all. Use your code for good!
Peace! โ๏ธ