Next.js Discord

Discord Forum

How should I nest different Providers?

Answered
Afghan Hound posted this in #help-forum
Open in Discord
Afghan HoundOP
How should i nest <SessionProvider/>(next-auth) <ThemeProvider/>(shadcn/ui) and <SidebarProvider/>(shadcn/ui) to not break anything with server and client components?
I my Sidebar i need await auth() from next-auth to get the session and display it in the sidebar.
this is my current code but it doesnt work:
import "./globals.css";

import type { Metadata } from "next";
import { SessionProvider } from "next-auth/react";
import AppSidebar from "@/components/app-sidebar";
import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar";
import { ThemeProvider } from "@/components/theme-provider";

export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
  return (
    <html lang="en" suppressHydrationWarning>
      <SessionProvider>
        <ThemeProvider                {/* client */}
          attribute="class"
          defaultTheme="system"
          enableSystem
          disableTransitionOnChange
        > 
          <SidebarProvider>            {/* client */}
            <AppSidebar variant="inset" />
            <main>
              <SidebarTrigger />      {/* server*/}
              {children}
            </main>
          </SidebarProvider>
        </ThemeProvider>
      </SessionProvider>
    </html>
  );
}

 ⨯ [Error: Server Functions cannot be called during initial render. This would create a fetch waterfall. Try to use a Server Component to pass data to Client Components instead.] {
  digest: '2018292887'
}
Answered by B33fb0n3
yea, only your Provider will go into the GlobalProvider. The rest stays the same in your layout:
import "./globals.css";

import type { Metadata } from "next";
import { SessionProvider } from "next-auth/react";
import AppSidebar from "@/components/app-sidebar";
import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar";
import { ThemeProvider } from "@/components/theme-provider";

export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
  return (
    <html lang="en" suppressHydrationWarning>
     {/* TODO: hopefully somewhere a body tag too?  */}
          <GlobalProvider>            {/* client */}
            <AppSidebar variant="inset" />
            <main>
              <SidebarTrigger />      {/* server*/}
              {children}
            </main>
          </GlobalProvider>

    </html>
  );
}
View full answer

9 Replies

@Afghan Hound But async functions cant be in client components or am i wrong?
I dont see any async stuff in the component your shared. If you mean the "session", that will be fetched: fetch it serverside (not in your layout)
Afghan HoundOP
now i get this error and i fully dont understand it :/
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
  return (
    <GlobalProviders>
      <AppSidebar variant="inset" />
      <main>
        {children}
      </main>
    </GlobalProviders>
  );
}

"use client"

import { SessionProvider } from "next-auth/react"
import { ThemeProvider } from "./theme-provider"
import { SidebarProvider } from "./ui/sidebar"

export default function GlobalProviders({ children }: Readonly<{ children: React.ReactNode }>) {
    return (
        <ThemeProvider
            attribute="class"
            defaultTheme="system"
            enableSystem
            disableTransitionOnChange
        >
            <SessionProvider>
                <SidebarProvider>
                    {children}
                </SidebarProvider>
            </SessionProvider>
        </ThemeProvider>
    )
}
@Afghan Hound now i get this error and i fully dont understand it :/ tsx export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) { return ( <GlobalProviders> <AppSidebar variant="inset" /> <main> {children} </main> </GlobalProviders> ); } tsx "use client" import { SessionProvider } from "next-auth/react" import { ThemeProvider } from "./theme-provider" import { SidebarProvider } from "./ui/sidebar" export default function GlobalProviders({ children }: Readonly<{ children: React.ReactNode }>) { return ( <ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange > <SessionProvider> <SidebarProvider> {children} </SidebarProvider> </SessionProvider> </ThemeProvider> ) }
yea, only your Provider will go into the GlobalProvider. The rest stays the same in your layout:
import "./globals.css";

import type { Metadata } from "next";
import { SessionProvider } from "next-auth/react";
import AppSidebar from "@/components/app-sidebar";
import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar";
import { ThemeProvider } from "@/components/theme-provider";

export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
  return (
    <html lang="en" suppressHydrationWarning>
     {/* TODO: hopefully somewhere a body tag too?  */}
          <GlobalProvider>            {/* client */}
            <AppSidebar variant="inset" />
            <main>
              <SidebarTrigger />      {/* server*/}
              {children}
            </main>
          </GlobalProvider>

    </html>
  );
}
Answer
@B33fb0n3 I dont see any async stuff in the component your shared. If you mean the "session", that will be fetched: fetch it serverside (not in your layout)
Dwarf Crocodile
what if he does this in his layout:

 const session = await auth();

 return (
    <GlobalProviders session={session}>
      <AppSidebar session={session} variant="inset" />
      <main>
        {children}
      </main>
    </GlobalProviders>
  );
happy to help