Setting up Convex in NextJS

January 18, 2024

What is Convex?

Convex is a full cloud backend designed to replace your database, server functions, backend functionality, and the interface all the way out to your application - Convex

I first heard about convex while watching a video of one of my favorite Youtube channels Web Dev Cody. In the video, he explains how he's switching from Postgres to a real-time database (watch the video here)

In the past, I tried coding a realtime messenger app using mongoDB. However, I remember the experience I had to go through to implement the realtime functionality. I had to use third-party APIs like Pusher which just added more burden to the developer experience and cost.

After watching Cody's video on Convex, I decided to try it out because it seemed to be packed with a lot of useful features like:

  • Functions that run on the backend
  • Database
  • File Storage
  • Authentication
  • Realtime updates

So, I tried setting up convex with NextJS.

Setting Up Convex

I installed Convex.

npm install convex && npm convex dev

You will receive a message containing instructions and information about your convex workspace. It also creates a .env.local file with the needed configurations.

.env.local
CONVEX_DEPLOYMENT=*******
NEXT_PUBLIC_CONVEX_URL=*******

Then, I will wrap my entire project with a <ConvexProvider />. (Since I'm not using Clerk for user management, I'm not using the <ConvexProviderWithClerk />). Read more in the docs

"use client";
 
import {ConvexProvider, ConvexReactClient} from "convex/react";
 
const convex = new ConvexReactClient(process.env.NEXT_PUBLICH_CONVEX_URL!)
 
export const ConvexClientProvider = ({children}: {children: React.ReactNode}) => {
  return (
    <ConvexProvider
      client={convex}
    >
      {children}
    </ConvexProvider>
  )
}
layout.tsx
export default function RootLayout({children}: {children: React.ReactNode}) => {
  return (
    <html lang="en">
      <ConvexClientProvider>
        {children}
      </ConvexClientProvider>
    </html>
  )
}

We can now test convex. Let's quickly try it out. First, I will make a simple user schema.

import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values"
 
export default defineSchema({
  user: defineTable({
    name: v.string(),
    email: v.string(),
    password: v.string(),
  })
})

And code a simple Convex function to mutate our data.

import { v } from "convex/values"
import { mutation } from "./_generated/server"
 
export const testing = mutation({
  args: {
	name: v.string(),
    email: v.string(),
    password: v.string(),
  },
  handler: async (ctx, args) => {
 
    await ctx.db.insert("user", {
	  name: args.name,
      email: args.email,
      password: args.password,
    })
  }
})

Add some code in our frontend...

const onSubmit = (values: z.infer<typeof LoginSchema>) => {
  const promise = createUser({
	name: values.name,
    email: values.email,
    password: values.password
  })
}

And it works! 😄

image

It was extremely fascinating to see the database update in realtime (rather than having to refresh every time I make a change).

Wrapping up: Convex is definitely a tool I will study more and use for my personal projects.

Maybe I should try building the same app with different services... 🤔


Go back to list