Next.js Discord

Discord Forum

Using `next/headers` in a monorepo app

Answered
German Shorthaired Pointer posted this in #help-forum
Open in Discord
German Shorthaired PointerOP
I just bumped my version from 14.0.2 to 14.2.1 and I've been getting this error:

You're importing a component that needs next/headers. That only works in a Server Component which is not supported in the pages/ directory. Read more: https://nextjs.org/docs/getting-started/react-essentials#server-components


These functions are being used in the right places. createServerClient inside server components, createBrowserClient inside client components. How do I resolve this

packages/supabase-common:

import {
  createServerClient as serverFn,
  createBrowserClient as browserFn,
  type CookieOptions,
} from '@supabase/ssr';
import { SupabaseClient, User as SupabaseUser } from '@supabase/supabase-js';
import { cookies as nextCookies } from 'next/headers';
import { NextResponse, type NextRequest } from 'next/server';

export type User = SupabaseUser;
const getSupabaseCredentials = (): {
  supabaseUrl: string;
  supabaseAnonKey: string;
} => {
  const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
  const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;

  if (!supabaseUrl || !supabaseAnonKey) {
    throw new Error(
      'Supabase URL and Anon Key must be set in environment variables.',
    );
  }

  return { supabaseUrl, supabaseAnonKey };
};

export const createServerClient = <T = any>({
  cookies,
}: {
  cookies: typeof nextCookies;
}): SupabaseClient<T> => {
  const cookieStore = cookies();
  const { supabaseUrl, supabaseAnonKey } = getSupabaseCredentials();

  return serverFn<T>(supabaseUrl, supabaseAnonKey, {
    cookies: {
      get: (name: string) => cookieStore.get(name)?.value,
    },
  });
};

export const createBrowserClient = <T = any>(): SupabaseClient<T> => {
  const { supabaseUrl, supabaseAnonKey } = getSupabaseCredentials();

  return browserFn<T>(supabaseUrl, supabaseAnonKey);
};

export const createRouteHandlerClient = <T = any>({
  cookies,
}: {
  cookies: typeof nextCookies;
}): SupabaseClient<T> => {
  const cookieStore = cookies();
  const { supabaseUrl, supabaseAnonKey } = getSupabaseCredentials();

  return serverFn<T>(supabaseUrl, supabaseAnonKey, {
    cookies: {
      get(name: string) {
        return cookieStore.get(name)?.value;
      },
      set(name: string, value: string, options: CookieOptions) {
        cookieStore.set({ name, value, ...options });
      },
      remove(name: string, options: CookieOptions) {
        cookieStore.set({ name, value: '', ...options });
      },
    },
  });
};

export const createMiddlewareClient = <T = any>({
  req,
  res,
}: {
  req: NextRequest;
  res: NextResponse;
}): SupabaseClient<T> => {
  const { supabaseUrl, supabaseAnonKey } = getSupabaseCredentials();

  return serverFn<T>(supabaseUrl, supabaseAnonKey, {
    cookies: {
      get(name: string) {
        return req.cookies.get(name)?.value;
      },
      set(name: string, value: string, options: CookieOptions) {
        req.cookies.set({
          name,
          value,
          ...options,
        });
        res = NextResponse.next({
          request: {
            headers: req.headers,
          },
        });
        res.cookies.set({
          name,
          value,
          ...options,
        });
      },
      remove(name: string, options: CookieOptions) {
        res.cookies.set({
          name,
          value: '',
          ...options,
        });
        res = NextResponse.next({
          request: {
            headers: req.headers,
          },
        });
        res.cookies.set({
          name,
          value: '',
          ...options,
        });
      },
    },
  });
};
Answered by Rafael Almeida
you need to separate them into two different files, you can't import a file that imports next/headers in a client component file
View full answer

2 Replies

you need to separate them into two different files, you can't import a file that imports next/headers in a client component file
Answer
German Shorthaired PointerOP
Ah that makes sense! Thank you