Question:
I’m working with Next.js and using Clerk for authentication alongside the Convex client. I encountered this error:
Error: Clerk: useAuth() called in static mode, wrap this component in
<ClerkProvider dynamic>
to make auth data available during server-side rendering.
I tried wrapping the component in <ClerkProvider dynamic>
, as the error suggested, and also added "use client"
at the top of the file. However, I’m still getting the error.
Here’s my setup:
-
Provider and Layout Setup:
I’m using
ConvexProviderWithClerk
along withClerkProvider
to passuseAuth
for authentication.Below is my
ConvexClientProvider
component:import { ClerkProvider, useAuth } from "@clerk/nextjs"; import { ConvexProviderWithClerk } from "convex/react-clerk"; import { ConvexReactClient } from "convex/react"; interface ConvexClientProviderProps { children: React.ReactNode; } const PUBLISHABLE_KEY = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY!; const convexUrl = process.env.NEXT_PUBLIC_CONVEX_URL!; const convex = new ConvexReactClient(convexUrl); export const ConvexClientProvider = ({ children }: ConvexClientProviderProps) => { return ( <ClerkProvider publishableKey={PUBLISHABLE_KEY}> <ConvexProviderWithClerk useAuth={useAuth} client={convex}> {children} </ConvexProviderWithClerk> </ClerkProvider> ); };
-
Root Layout Component:
Here’s the structure of my
RootLayout
component, which wraps the app inConvexClientProvider
:import { Metadata } from "next"; import localFont from "next/font/local"; import "./globals.css"; import { ConvexClientProvider } from "@/providers/convex-client-provider"; export const metadata: Metadata = { title: "Create Next App", description: "Generated by create next app", }; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="en"> <body> <ConvexClientProvider>{children}</ConvexClientProvider> </body> </html> ); }
Things I’ve Tried:
- Adding
"use client"
at the top of theRootLayout
file andConvexClientProvider
. - Wrapping the
ConvexClientProvider
with<ClerkProvider dynamic>
as suggested in the error message.
2
Answers
You need to import ClerkProvider,useAuth from "@clerk/clerk-react";
import { ClerkProvider, useAuth } from "@clerk/clerk-react";
It is mentioned here in convex docs:
https://docs.convex.dev/auth/clerk
I had the same issue. This resolved mine. Use dynamic import for ConvexProviderWithClerk. Enjoy!
https://github.com/jeremy-clerk/clerk-auth-convex-chat/blob/upgrade/providers/ConvexClientProvider.tsx
Source:https://discord.com/channels/856971667393609759/1304189273553109022/1304579659677040660
The cause explained in Clerk Discord:
https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#using-context-providers
The problem is that the ConvexProvider takes in the
useAuth()
hook and NextJS is trying to statically render that provider. We now statically render the<ClerkProvider />
by default – unless you pass the dynamic prop – buuuttt – the problem is that Convex is still trying to statically render, even though it’s within a client boundary. It could be the way they’re doing imports or the way NextJS is trying to resolve packages.It seems like it stems from nesting the Context Providers. If Convex added the
"use client";
directive – this should be fixed. When I downgraded the packages, it changes to Clerk rendering dynamically by default, which forces everything underneath it to be dynamically rendered. It should be noted that the"use client";
directive just means that the code will be included in the Client bundle – it can still be evaluated by NextJS.What I did, was to use an older school method called a "dynamic import" by doing this with the
ssr: false
option – I forced NextJS to not evaluate the import until the page loads – which resolves our issue of Convex throwing throwing the error aboutuseAuth()
. This is the error that I was finding in the server logs:Error: Clerk: useAuth() called in static mode, wrap this component in <ClerkProvider dynamic> to make auth data available during server-side rendering.
Which came from the server – and we were wrapping it in a
<ClerkProvider dynamic>
but for whatever reason, it was still trying to eval this.