Full Stack Application SETUP with Next.js, Clerk, and Convex

Full Stack Application SETUP with Next.js, Clerk, and Convex

Hello!

Today we'll be going over how to set up a basic Next.js/React application with Clerk and Convex.

I'll be setting up the infrastructure for a basic web application using these technologies. This tutorial will hopefully show you how to set up and integrate Next.js with Clerk and Convex, and in future installments, I may show some tutorials building on this base code, showing how to use Convex!

What are Clerk and Convex?

If you aren't familiar with Clerk, it is a very nice suite of embeddable UIs, flexible APIs, and an admin dashboard to authenticate and manage users. In our application, we will be using it for authentication.

If you aren't familiar with Convex, it is a backend application platform that provides many useful features.

  • A realtime database

  • Functions

  • Function scheduling

  • File storage

In our application, we will be using Convex to manage our backend stuff. We will utilize its database to store user-specific data.


Creating the Clerk and Convex apps

First, if you don't have an account with Clerk, create one. Then go to the following link to create a new application with Clerk:

New Clerk App

Now, it will prompt you for details on the sign-up component. You can call the application whatever you want, and select the sign in options you want for your app. You can change these options later as well.

After that, we are finished setting up our Clerk application (for now)! Keep that window open, though, we'll need it in a sec.

Next, we are going to configure the Convex app. Go to your Convex dashboard (or make an account if you haven't already), and create a new project. This should be relatively straightforward.

Navigate to the "URL and Deploy Key" section. We'll need info from here in a second.

Environment Setup

Now it's time to create our next application. Open up a fresh terminal in VSCode (or whatever editor you use). Type in the following command to create a new Next.js project:

npx create-next-app@latest --tailwind

It will prompt you with some questions, you can configure the project to your liking. Besides the name of the project, I will be selecting the default answer for each of them (including using TypeScript).

Now, make sure to navigate to that folder in your text editor. Next, you can run the command:

npm install convex

This will install convex into your projects.

Now, we will run the command:

npx convex dev

This will prompt you to log in with GitHub (if you aren't already), which will be connected to your Convex account. It will then ask you if you want to use an existing project or create a new one, make sure you choose an existing one, since we made that one earlier. Now, select the project you created earlier in the tutorial.

You'll notice that this created a convex folder in the root of our project, as well as a .env.local file. If you look in the .env.local file, you'll see environment variables have already been set up for CONVEX_DEPLOYMENT and NEXT_PUBLIC_CONVEX_URL. Awesome!

Next, we want to integrate Clerk into our project. Run the following command in the terminal:

npm install @clerk/nextjs

Now Clerk is installed into our project. Next, we want to add our environment variables for Clerk into our project. Navigate to your Clerk dashboard again, then go to API Keys on the sidebar. You're going to want to copy the code for Next.js there.

Paste that into your .env.local file. So now you should have 4 environment variables in that file.

Wrapping the application

Now, we are ready to actually start writing some code!

First, you can create a components folder in your root directory, and then create a providers folder inside of that one. Create a file called convex-provider.tsx in that folder, and copy this code in there:

"use client";

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

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

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

Convex comes with a nice provider that integrates with Clerk, so we are using that here.

Next, head to your layout.tsx, which will be in the app folder. We are going to wrap our entire application using the Convex provider:

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import { ConvexClientProvider } from '@/components/providers/convex-provider';
import "./globals.css";

const inter = Inter({ subsets: ["latin"] });

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" suppressHydrationWarning>
      <body className={inter.className}>
        <ConvexClientProvider>
            {children}
        </ConvexClientProvider>
      </body>
    </html>
  )
}

Clerk JWT Template

Creating a JWT Template for Clerk that integrates with Convex is easy, as there is already a token template for Convex that is provided by Clerk.

First, navigate to the JWT Templates section on the dashboard of Clerk.

Now, click the "New Template" button. This will give you some template options, and you can select Convex.

Next, there will be a section that says "Issuer". Copy that URL.

Now navigate to your Convex dashboard, and go to Settings > Environment Variables. Create a new environment variable and call it CLERK_JWT_ISSUER_DOMAIN, and provide the Issuer value from the last step.

All done! Now your JWT template is set up.

Sign In Example

To allow users to sign in, you can write code similar to this:

import { SignInButton } from "@clerk/nextjs";
import Image from "next/image";

export default function Home() {
  return (
      <SignInButton afterSignInUrl="/"/>
  );
}

This will render a tiny button that takes users to the sign-in page. You will likely use the SignInButton component from @clerk/nextjs no matter how you plan on handling sign in.

Bye!

In the next part of this post, I will go more in-depth into creating the application, showing examples of how to use the Convex database to store data for specific users. Stay tuned for that, but hopefully this article helped you set up your project in a quick, efficient manner!

Thanks for reading!