#Nextjs + Clerk + Convex

10 messages · Page 1 of 1 (latest)

supple grottoBOT
#

Hi @hasty herald. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

Implementing Clerk + Next.js + Convex

To implement Clerk authentication with Next.js and Convex, you'll need to follow these steps:

Setup Process

  1. Create a Next.js app with Convex

    The easiest way to get started is to use the Convex CLI:

    npm create convex@latest -- -t nextjs-clerk
    

    This creates a project with Next.js, Clerk, and Convex already configured Convex & Clerk.

  2. If you have an existing project, you'll need to:

    • Install the required packages:

      npm install convex @clerk/nextjs
      
    • Set up Clerk by following their Next.js quickstart

    • Create a JWT template in Clerk dashboard named "convex"

  3. Configure Convex with Clerk

    Create an auth config file in your Convex folder:

    // convex/auth.config.ts
    export default {
      providers: [
        {
          domain: "<https://your-issuer-url.clerk.accounts.dev/",>
          applicationID: "convex",
        },
      ]
    };
    
  4. Create a Client Provider Component

#
   // app/ConvexClientProvider.tsx
   "use client";
   
   import { ConvexProviderWithClerk } from "convex/react-clerk";
   import { ConvexReactClient } from "convex/react";
   import { ClerkProvider, useAuth } from "@clerk/nextjs";
   import { ReactNode } from "react";
   
   const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);
   
   export default function ConvexClientProvider({
     children,
   }: {
     children: ReactNode;
   }) {
     return (
       <ClerkProvider
         publishableKey={process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY!}
       >
         <ConvexProviderWithClerk client={convex} useAuth={useAuth}>
           {children}
         </ConvexProviderWithClerk>
       </ClerkProvider>
     );
   }
  1. Add the provider to your layout

    In your app/layout.tsx, wrap your application with the ConvexClientProvider.

Server-Side Authentication

For server components, server actions, or route handlers, you can use fetchQuery, fetchMutation, or fetchAction with an auth token:

import { fetchMutation } from "convex/nextjs";
import { getAuth } from "@clerk/nextjs/server";
import { api } from "@/convex/_generated/api";

// In a server action or route handler
const token = await getToken({ template: "convex" });
await fetchMutation(
  api.myModule.myMutation,
  { /* args */ },
  { token }
);

Common Issues

If you're using static routes in Next.js, you might encounter issues with Clerk's authentication. This is because Clerk requires the ClerkProvider to be dynamic when used with Convex, which can conflict with static rendering Discord support thread.

For Next.js 15 with Clerk 6, the recommended approach is to use the latest Convex template which properly configures the integration.

#

Authentication Flow

Under the hood, the authentication flow works like this:

  1. User logs in via Clerk
  2. ConvexProviderWithClerk fetches an auth token from Clerk
  3. The token is passed to Convex for validation
  4. Your Convex backend can then access user identity via ctx.auth.getUserIdentity()

For a complete example, check out the NotesGPT project which uses this stack.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@hasty herald Kapa.ai is still learning and improving, please let me know how I did by reacting below.

hasty herald
#

@supple grotto So in my layout.tsx, I can remove clerk & convex if i call Client Provider?

supple grottoBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

Based on your code example, you're asking if you can remove the ClerkProvider from your layout since you're using a ConvexClientProvider. Let me clarify this for you.

If your ConvexClientProvider already includes the ClerkProvider inside it (as shown in the previous example), then yes, you should remove the outer ClerkProvider from your layout to avoid duplication.

Looking at a typical ConvexClientProvider implementation with Clerk:

// ConvexClientProvider.tsx
"use client";

import { ClerkProvider, useAuth } from "@clerk/clerk-react";
import { ConvexProviderWithClerk } from "convex/react-clerk";
import { ConvexReactClient } from "convex/react";
import { ReactNode } from "react";

const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);

export function ConvexClientProvider({ children }: { children: ReactNode }) {
  return (
    <ClerkProvider publishableKey={process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY!}>
      <ConvexProviderWithClerk client={convex} useAuth={useAuth}>
        {children}
      </ConvexProviderWithClerk>
    </ClerkProvider>
  );
}

If your ConvexClientProvider is structured like this, then your layout should be simplified to:

export default function AppLayout({ children }: { children: React.ReactNode }) {
    return (
        <ThemeProvider attribute="class" defaultTheme="dark" disableTransitionOnChange>
            <PostHogProvider>
                <ConvexClientProvider>
                    {children}
                </ConvexClientProvider>
            </PostHogProvider>
        </ThemeProvider>
    );
}
#

This avoids the issue of "doubling-up" on providers, which can cause authentication problems as mentioned in a Discord support thread where a user experienced issues with getUserIdentity returning null due to having multiple Clerk providers.

However, if your ConvexClientProvider only contains the ConvexProviderWithClerk without wrapping it in a ClerkProvider, then you should keep the outer ClerkProvider in your layout.

The key is to ensure you have exactly one instance of each provider in your component tree, with Clerk wrapping Convex (not the other way around).

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@hasty herald Kapa.ai is still learning and improving, please let me know how I did by reacting below.