By default, Next.js attempts to optimize your application by statically generating pages at build-time that do not depend on data from the request. However, authentication data is inherently dynamic and depends on the request, meaning that it is not available at build-time.
To facilitate Next.js's default behavior, Clerk provides an opt-in approach to accessing authentication data so that you can opt-in specific routes to dynamic rendering, while still using statically rendered pages for others.
The following options are available for accessing authentication data:
The auth() helper can only be used in Server Components, but the data can be passed to Client Components if desired. Without Cache Components, it opts your entire route into dynamic rendering.
The useAuth() hook can only be used in Client Components. Due to Next.js's default behavior, these components will be statically rendered. However, you can wrap them with <ClerkProvider dynamic> to opt them into dynamic rendering.
Note
New Next.js apps enable Cache Components, which prerenders each page up to its <Suspense> boundaries instead of rendering the whole route dynamically. If your app sets cacheComponents: true, see Cache Components for where to add <Suspense> boundaries.
The auth() helper returns the user's authentication state in Server Components. The data can be passed to Client Components if desired. This is a dynamic API that relies on request-time data. Without Cache Components, using auth() opts your entire route into dynamic rendering, as in the following example. With Cache Components, only the content inside the <Suspense> boundary around auth() renders at request time, so this page needs a boundary, such as a loading.tsx file.
import { auth } from'@clerk/nextjs/server'// This page will be dynamically rendered at request timeexportdefaultasyncfunctionPage() {const { userId } =awaitauth()// This will be immediately available on first renderconsole.log(userId)return <p>Hello, {userId}</p>}
useAuth() provides authentication data in Client Components. Due to Next.js's default behavior, these components will be statically rendered. If that's fine with you, see the reference docs for more information, like code examples.
However, if you'd like the components that use useAuth() to be dynamically rendered, you can wrap them with <ClerkProvider dynamic>. Wrap <ClerkProvider dynamic> in <Suspense> so that the boundary fallback is included in the prerendered HTML. If you're using Cache Components, the boundary is required, or next build fails.
Warning
It is not recommended and not optimal to wrap your entire application with <ClerkProvider dynamic> as this opts all routes into dynamic rendering, when some routes may be better suited for static rendering. If you're not sure if a route is better suited for static or dynamic rendering, see the Next.js guide on static and dynamic rendering.
The following example demonstrates how to use <ClerkProvider dynamic> in a page's layout in order to opt it into dynamic rendering. In this case, the root layout would still be wrapped with <ClerkProvider> to provide the authentication context to the entire app, but without the dynamic prop being passed as to not opt your entire app into dynamic rendering.
'use client'import { useAuth } from'@clerk/nextjs'exportdefaultfunctionPage() {const { userId,sessionId,isSignedIn } =useAuth()// All of these will be immediately available on first renderconsole.log(userId, sessionId, isSignedIn)return ( <div> <h1>Test Page</h1> <p>User ID: {userId}</p> </div> )}
New Next.js apps created with create-next-app enable Cache Components by setting cacheComponents: true in next.config.ts. With Cache Components, Next.js prerenders as much of each page as it can at build time and streams in the parts that depend on the request. Any code that reads request data must run inside a <Suspense> boundary. Otherwise, next build fails with an error like the following:
Error: Route "/": Next.js encountered uncached or runtime data during prerendering.
Clerk reads the user's session from the request, so the following need a <Suspense> boundary:
Place each <Suspense> boundary as close as possible to the component that reads auth data. Next.js prerenders everything outside the boundary as static HTML, shows the boundary's fallback in its place, and streams in the auth-dependent content at request time.
The following example demonstrates how to wrap the <Show> components in a root layout's header. <ClerkProvider> and <header> stay outside the boundary, so they're part of the prerendered page.
If a Server Component page renders <Show>, wrap the <Show> in <Suspense> the same way.
If a page calls auth() or currentUser() to render data, move the call into an async child component inside <Suspense>, and keep the page itself synchronous. The following example demonstrates how to call currentUser() in a page. The page's heading is prerendered, while the <Greeting> component reads the user inside a <Suspense> boundary and streams in at request time.
app/dashboard/page.tsx
import { currentUser } from'@clerk/nextjs/server'import { Suspense } from'react'exportdefaultfunctionPage() {return ( <main> <h1>Dashboard</h1> <Suspensefallback={<p>Loading...</p>}> <Greeting /> </Suspense> </main> )}asyncfunctionGreeting() {constuser=awaitcurrentUser()if (!user) {return <p>Sign in to see your dashboard.</p> }return <p>Welcome, {user.firstName}!</p>}
If a page gates its whole render with auth.protect(), redirectToSignIn(), or redirect(), leave the page unchanged and add a loading.tsx file next to it. Next.js wraps the page in a <Suspense> boundary that uses loading.tsx as its fallback, so the page can call auth() at the top level. The trade-off is that Next.js prerenders only the layout and the fallback, not any of the page's own content. Next.js also sends the response status as soon as it starts streaming, so a signed-out or unauthorized request to that page gets HTTP 200 with the redirect or 404 streamed in, not a 307 or 404. To send signed-out users a real 307, add an early redirect in clerkMiddleware(), which runs before rendering, and keep the page's own check.
<SignIn />, <SignUp />, <UserProfile />, and <OrganizationProfile /> read the current URL with Next.js's usePathname() and useParams() hooks to support path-based routing. On an optional catch-all route, such as app/sign-in/[[...sign-in]]/page.tsx, Next.js only knows the URL at request time. Without a <Suspense> boundary, next build fails with an error like the following:
Error: Route "/sign-in/[[...sign-in]]": Next.js encountered URL data `usePathname()` in a Client Component outside of `<Suspense>`.
The following example demonstrates how to wrap <SignIn /> in <Suspense>. The same applies to the other components, even when you pass the path prop or render the component from a Client Component.
auth() and currentUser() read the request's headers, which aren't available inside a 'use cache' function. Calling them there fails with the following error:
Error: Route "/": `headers()` can't be read inside `"use cache"`. Read it outside the cached function and pass what you need as an argument.Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
Instead, read the user's ID outside the cached function and pass it in as an argument. Next.js includes a cached function's arguments in its cache key, so each user gets their own cache entry.
The following example demonstrates how to cache a user's projects. The <Projects> component reads the user's ID with auth() inside a <Suspense> boundary and passes it to getProjects(), which caches the result for that user. cacheTag() tags the entry with the user's ID so you can invalidate that user's cache when their data changes, and cacheLife() sets how long the entry lasts.
Pass the user's ID, or the Organization ID for Organization-scoped data, as an argument to every cached function that returns data for that user or Organization. If the cache key doesn't include it, Next.js can serve one user's cached data to another.