How to Set Up Clerk Authentication with Convex in a Next.js Project

Javascript Engineer, Fashion Lover.
Integrating authentication shouldn't feel like a chore. By combining Clerk (for identity management) and Convex (for your backend/database), you get a powerhouse stack that handles user sessions, data synchronization, and security with minimal overhead.
This guide walks you through the end-to-end setup to get your Next.js application production-ready.
Prerequisites
Before we dive in, make sure you have the following:
Node.js installed on your machine.
A basic understanding of Next.js (App Router is recommended).
A fresh or existing Next.js project.
Step 1: Create a Next.js Project
If you’re starting from scratch, run the following commands in your terminal:
npx create-next-app@latest my-app cd my-app yarn run dev
Step 2: Set Up Your Clerk Account
Head over to Clerk.com and create a free account.
Create a new application in the Clerk Dashboard.
Copy your Publishable Key and Secret Key.
Create a .env.local file in your project root and add them:
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxxxxxxxx CLERK_SECRET_KEY=sk_test_xxxxxxxxx
Step 3: Install Clerk
Install the Clerk Next.js SDK:
yarn install @clerk/nextjs
Step 4: Set Up Your Convex Account
Go to Convex.dev and sign up.
Create a new project.
Step 5: Initialize Convex in Your Project
Run the following command to link your local project to the Convex backend:
yarn install convex npx convex dev
Note: This command creates a convex/ folder and generates development keys, which are automatically added to your .env.local file. You should see a variable like:
NEXT_PUBLIC_CONVEX_URL=https://example-123.convex.cloud.
Step 6: Create a Global Providers File
To make authentication state available throughout your app, create a providers.tsx (or .jsx) file in your app directory.
Install Required Dependencies
yarn install convex && yarn install convex @clerk/nextjs
Providers Implementation
"use client";
import { ClerkProvider, useAuth } from "@clerk/nextjs"; import { ConvexProviderWithClerk } from "convex/react-clerk"; import { ConvexReactClient } from "convex/react";
const convex = new ConvexReactClient( process.env.NEXT_PUBLIC_CONVEX_URL! );
export function Providers({children,}: {children: React.ReactNode;}) { return ( <ClerkProvider> <ConvexProviderWithClerk client={convex} useAuth={useAuth}> {children} </ConvexProviderWithClerk> </ClerkProvider> ); }
Step 7: Wrap Your Application
In your app/layout.tsx, wrap the children with the Providers component you just created.
import { Providers } from "./providers";
export default function RootLayout({children,}: {children: React.ReactNode;}) { return ( <html lang="en"> <body> <Providers>{children}</Providers> </body> </html> ); }
Step 8: Configure Webhooks for User Sync
To keep your Convex database in sync with Clerk users, you need to set up a webhook.
Open your Convex Dashboard.
Go to Settings → General.
Copy the HTTP Actions URL (ensure it ends in .site).
- Example: https://example-actions-222.convex.site
Step 9: Register the Webhook in Clerk
Go to the Clerk Dashboard → Webhooks.
Click Add Endpoint.
Paste your Convex HTTP URL and append /clerk-users-webhook.
- Final URL: https://example-actions-222.convex.site/clerk-users-webhook
Select the events you want to listen to (e.g., user.created, user.updated, session.created).
Step 10: Secure Your Webhook
Clerk provides a Signing Secret for your webhook. Add this to your .env.local:
CLERK_WEBHOOK_SECRET=whsec_xxxxxxxxx
Step 11: Create a JWT Template in Clerk
Convex needs a specific JWT (JSON Web Token) to verify users.
In Clerk, go to JWT Templates → New Template.
Select Convex.
Ensure the claims look like this:
JSON
{
"aud": "convex",
"name": "{{user.full_name}}",
"role": "{{user.public_metadata}}",
"email": "{{user.primary_email_address}}",
"picture": "{{user.image_url}}",
"nickname": "{{user.username}}",
"given_name": "{{user.first_name}}",
"updated_at": "{{user.updated_at}}",
"family_name": "{{user.last_name}}",
"phone_number": "{{user.primary_phone_number}}"
}
- Save the template.
Step 12: Copy the Issuer URL
Copy the Issuer URL from the template you just created and add it to .env.local:
NEXT_PUBLIC_CLERK_FRONTEND_API_URL=https://your-app-name.clerk.accounts.dev
Step 13: Create auth.config.js
In the root of your project, create auth.config.js. This tells Convex how to validate the Clerk tokens.
export default {providers: [{ domain: process.env.NEXT_PUBLIC_CLERK_FRONTEND_API_URL, applicationID: "convex", }]};
Step 14: Final Production Prep
Before going live, ensure your production environment variables are set:
Copy all values from .env.local.
Paste them into the Environment Variables section of both your Clerk and Convex production dashboards.
You now have a fully functional, secure authentication flow. Users can sign in via Clerk, and their identity is automatically verified by Convex via JWT.
Don't forget to setup your Convex Schema and have a happy development!



