The ClerkProvider component is the root provider that wraps your Next.js application and provides authentication context to all child components. It initializes Clerk and manages authentication state across your application.
The ClerkProvider component must wrap your application to enable Clerk authentication. It behaves differently based on your Next.js router:
/**
* Root provider component for Clerk authentication
* @param props - ClerkProvider configuration props
* @returns Provider component wrapping application
*/
function ClerkProvider(props: NextClerkProviderProps): JSX.Element;
interface NextClerkProviderProps {
/**
* Optional override for NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY environment variable
* If not provided, ClerkProvider automatically uses NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
*/
publishableKey?: string;
/**
* If true, invokes Next.js middleware every time client-side auth state changes
* (sign-out, sign-in, organization switch, etc.)
* This allows auth-dependent logic in middleware to re-execute
* @default true
*/
__unstable_invokeMiddlewareOnAuthStateChange?: boolean;
/**
* If true, opts into dynamic rendering for auth data
* Makes auth data available to all wrapped components
* @default false
*/
dynamic?: boolean;
/**
* Appearance customization options
* Controls theming, layout, and styling of Clerk components
*/
appearance?: Appearance;
/**
* Localization options
* Configure language and locale for Clerk UI components
*/
localization?: Localization;
/**
* Default sign-in URL
* Where to redirect users when signing in
*/
signInUrl?: string;
/**
* Default sign-up URL
* Where to redirect users when signing up
*/
signUpUrl?: string;
/**
* Default URL after successful sign-in
*/
afterSignInUrl?: string;
/**
* Default URL after successful sign-up
*/
afterSignUpUrl?: string;
/**
* Custom navigation function
* Override default navigation behavior
*/
navigate?: (to: string) => Promise<unknown> | void;
/**
* Clerk session token template
* For custom JWT templates
*/
clerkJSVariant?: string;
/**
* React children components
*/
children: React.ReactNode;
}For App Router applications, ClerkProvider should wrap your root layout as a server component.
/**
* App Router setup example
* ClerkProvider wraps the root layout
*/
// app/layout.tsx
import { ClerkProvider } from '@clerk/nextjs';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<ClerkProvider>
<html lang="en">
<body>{children}</body>
</html>
</ClerkProvider>
);
}Usage Example with Custom Options:
// app/layout.tsx
import { ClerkProvider } from '@clerk/nextjs';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<ClerkProvider
appearance={{
baseTheme: 'dark',
variables: { colorPrimary: '#0070f3' },
}}
signInUrl="/sign-in"
signUpUrl="/sign-up"
afterSignInUrl="/dashboard"
afterSignUpUrl="/onboarding"
>
<html lang="en">
<body>{children}</body>
</html>
</ClerkProvider>
);
}For Pages Router applications, ClerkProvider should wrap your _app component as a client component.
/**
* Pages Router setup example
* ClerkProvider wraps the App component
*/
// pages/_app.tsx
import { ClerkProvider } from '@clerk/nextjs';
import type { AppProps } from 'next/app';
export default function App({ Component, pageProps }: AppProps) {
return (
<ClerkProvider {...pageProps}>
<Component {...pageProps} />
</ClerkProvider>
);
}Usage Example with Server-Side Props:
// pages/_app.tsx
import { ClerkProvider } from '@clerk/nextjs';
import type { AppProps } from 'next/app';
export default function App({ Component, pageProps }: AppProps) {
return (
<ClerkProvider
{...pageProps}
appearance={{
baseTheme: 'light',
elements: {
formButtonPrimary: 'bg-blue-500 hover:bg-blue-600',
},
}}
>
<Component {...pageProps} />
</ClerkProvider>
);
}
// pages/index.tsx
import { buildClerkProps, getAuth } from '@clerk/nextjs/server';
import type { GetServerSideProps } from 'next';
export const getServerSideProps: GetServerSideProps = async (ctx) => {
const { userId } = getAuth(ctx.req);
return {
props: {
...buildClerkProps(ctx.req),
userId,
},
};
};
export default function Home({ userId }: { userId: string | null }) {
return <div>User ID: {userId}</div>;
}ClerkProvider automatically reads from environment variables if props are not provided:
/**
* Environment variables used by ClerkProvider
*/
interface ClerkEnvironmentVariables {
/**
* Publishable key for Clerk application
* Required for client-side initialization
* @env NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
*/
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: string;
/**
* Secret key for Clerk application
* Used for server-side authentication
* @env CLERK_SECRET_KEY
*/
CLERK_SECRET_KEY?: string;
/**
* Custom sign-in URL
* @env NEXT_PUBLIC_CLERK_SIGN_IN_URL
*/
NEXT_PUBLIC_CLERK_SIGN_IN_URL?: string;
/**
* Custom sign-up URL
* @env NEXT_PUBLIC_CLERK_SIGN_UP_URL
*/
NEXT_PUBLIC_CLERK_SIGN_UP_URL?: string;
/**
* URL to redirect after sign-in
* @env NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL
*/
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL?: string;
/**
* URL to redirect after sign-up
* @env NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL
*/
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL?: string;
}Example .env.local:
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxxxx
CLERK_SECRET_KEY=sk_test_xxxxx
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/dashboard
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/onboardingThe appearance prop allows comprehensive theming and styling customization.
/**
* Appearance customization interface
*/
interface Appearance {
/**
* Base theme configuration
* Use preset themes or custom theme object
*/
baseTheme?: Theme | Theme[];
/**
* CSS variables for global styling
* Colors, fonts, spacing, etc.
*/
variables?: {
colorPrimary?: string;
colorBackground?: string;
colorText?: string;
colorTextSecondary?: string;
colorDanger?: string;
colorSuccess?: string;
colorWarning?: string;
colorNeutral?: string;
fontFamily?: string;
fontSize?: string;
borderRadius?: string;
spacingUnit?: string;
};
/**
* Element-specific styling
* Target specific Clerk UI elements
*/
elements?: {
[elementName: string]: string | React.CSSProperties;
};
/**
* Layout configuration
* Control component layout and structure
*/
layout?: {
socialButtonsPlacement?: 'top' | 'bottom';
socialButtonsVariant?: 'blockButton' | 'iconButton';
shimmer?: boolean;
termsPageUrl?: string;
privacyPageUrl?: string;
helpPageUrl?: string;
};
}Usage Example:
import { ClerkProvider } from '@clerk/nextjs';
import { dark } from '@clerk/themes';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<ClerkProvider
appearance={{
baseTheme: dark,
variables: {
colorPrimary: '#6366f1',
colorBackground: '#1a1a1a',
fontFamily: 'Inter, sans-serif',
borderRadius: '0.5rem',
},
elements: {
formButtonPrimary: 'bg-indigo-600 hover:bg-indigo-700',
card: 'shadow-xl',
headerTitle: 'text-2xl font-bold',
formFieldInput: 'rounded-lg border-gray-700',
},
layout: {
socialButtonsPlacement: 'bottom',
socialButtonsVariant: 'iconButton',
shimmer: true,
},
}}
>
<html lang="en">
<body>{children}</body>
</html>
</ClerkProvider>
);
}Configure language and locale for Clerk UI components.
/**
* Localization configuration
*/
interface Localization {
/**
* Locale code (e.g., 'en-US', 'es-ES', 'fr-FR')
*/
locale?: string;
/**
* Custom text overrides
* Override default text for any Clerk UI element
*/
localizations?: {
[key: string]: string | ((params?: any) => string);
};
}Usage Example:
import { ClerkProvider } from '@clerk/nextjs';
import { esES } from '@clerk/localizations';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<ClerkProvider
localization={{
...esES,
localizations: {
signIn: {
start: {
title: 'Iniciar sesión',
subtitle: 'Ingresa tus credenciales',
},
},
},
}}
>
<html lang="es">
<body>{children}</body>
</html>
</ClerkProvider>
);
}The dynamic prop controls whether auth data is available during server-side rendering.
/**
* Dynamic rendering configuration
* When true, opts into dynamic rendering for auth data
*/
// app/layout.tsx
import { ClerkProvider } from '@clerk/nextjs';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<ClerkProvider dynamic={true}>
<html lang="en">
<body>{children}</body>
</html>
</ClerkProvider>
);
}Impact of Dynamic Rendering:
dynamic={true}: Auth data is available in Server Components, but pages cannot be statically generateddynamic={false} (default): Better performance with static generation, but auth data only available on clientThe __unstable_invokeMiddlewareOnAuthStateChange prop controls middleware re-execution on auth state changes.
/**
* Middleware integration configuration
* Controls when middleware re-executes
*/
// app/layout.tsx
import { ClerkProvider } from '@clerk/nextjs';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<ClerkProvider __unstable_invokeMiddlewareOnAuthStateChange={true}>
<html lang="en">
<body>{children}</body>
</html>
</ClerkProvider>
);
}Use Cases:
Example with Middleware:
// middleware.ts
import { clerkMiddleware } from '@clerk/nextjs/server';
export default clerkMiddleware((auth, req) => {
// This logic runs every time auth state changes on client
// when __unstable_invokeMiddlewareOnAuthStateChange is true
if (!auth().userId && req.nextUrl.pathname.startsWith('/dashboard')) {
return auth().redirectToSignIn();
}
});
export const config = {
matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'],
};ClerkProvider is fully typed with TypeScript support.
/**
* Type-safe ClerkProvider usage
*/
import type { NextClerkProviderProps } from '@clerk/nextjs';
const providerConfig: NextClerkProviderProps = {
publishableKey: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
appearance: {
variables: {
colorPrimary: '#0070f3',
},
},
dynamic: true,
};
// Use with ClerkProvider
<ClerkProvider {...providerConfig}>
{children}
</ClerkProvider>