Hey, I'm Temur! ๐Ÿ‘‹

All Items

Setup CockroachDB with Next.js 13.

NextJS

CockroachDB

SQL

Prisma

TypeScript

ORM

Created @ September 15, 2023 (1y ago)

9 min read

  1. Overview
  2. Installation
  3. Prisma Setup
  4. CockroachDB Setup
  5. Example
  6. Testing

โญ๏ธ Overview

In this article, we will explore the process of setting up CockroachDB, a distributed SQL database, with Next.js 13, a popular React framework. We will leverage the power of Prisma, a TypeScript-based ORM, to seamlessly interact with CockroachDB and build robust, scalable web applications.

By following this guide, you will learn how to configure your development environment, establish a connection between Next.js and CockroachDB, and utilize Prisma for efficient data handling.

๐Ÿ“ฆ Installation

  1. Node.js: Before we get started, make sure you have Node.js installed on your system. You can download and install Node.js from the official website. To verify your Node.js installation, open your terminal or command prompt and run the following command:
node -v
  1. Next.js: Now, we'll set up Next.js, a powerful React framework. To install the latest version of Next.js, we'll use the following script, which initializes a new Next.js project with default settings:
npx create-next-app@latest
  1. Prisma: Now that we have Next.js installed, we'll install Prisma, a TypeScript-based ORM, to streamline our data operations. To get started with Prisma, run these commands in your terminal:
npm install @prisma/client
npm install -D prisma

๐Ÿ”ผ Prisma Setup

After installing Prisma, you'll need to configure it to generate your database client and run it alongside Next.js. To do this, follow these steps:

Open your package.json file, which is located in the root directory of your project.

Find the "scripts" section in your package.json file and modify the "build" script with the following:

"scripts": {
    "dev": "next dev",
    "build": "next build && prisma generate && next lint",
    "start": "next start"
}
๐Ÿ’ก
  • prisma generate generates the Prisma client based on your database schema. It ensures that your application can interact with the database using Prisma.
  • next lint (optional) runs ESLint on your project to ensure that your code is free of lint errors.

Now, let's create a prisma directory in the root directory of your project. This directory will contain your database schema and migrations. To do this, run the following command in your terminal:

npx prisma init

This command will create a prisma directory with the following files:

  • schema.prisma: This file contains your database schema, which defines the structure of your database tables and columns.
  • .env: This file contains your database connection string, which is used to establish a connection between your application and your database.
๐Ÿ†˜

Make sure to add your .env file to your .gitignore file to prevent your database connection string from being exposed.

We are going to make a few changes to these files to ensure that Prisma can generate our database client and run it alongside Next.js.

Open your schema.prisma file and modify it with the following:

generator client {
  provider = "prisma-client-js"
}
 
datasource db {
  provider     = "cockroachdb"
  url          = env("DATABASE_URL")
  relationMode = "prisma"
}
๐Ÿ’ก
  • prisma-client-js specifies that we want to use the Prisma client library as our database client.
  • cockroachdb specifies that we want to use CockroachDB as our database provider.
  • url specifies that we want to use the DATABASE_URL environment variable for our database connection string.
  • relationMode specifies that we want to use Prisma's relation mode.

Lastly, let's create a lib folder to keep our database-related code separate and organized. To do this, create a new folder named lib in the src directory of your project or run the following command in your terminal:

mkdir src/lib

Create a db.ts file inside the lib folder and add the following code to it:

import { PrismaClient } from '@prisma/client';
import 'server-only';
 
declare global {
	// eslint-disable-next-line no-var, no-unused-vars
	var cachedPrisma: PrismaClient;
}
 
export let prisma: PrismaClient;
if (process.env.NODE_ENV === 'production') {
	prisma = new PrismaClient();
} else {
	if (!global.cachedPrisma) {
		global.cachedPrisma = new PrismaClient();
	}
	prisma = global.cachedPrisma;
}
๐Ÿ’ก
  • import 'server-only' imports the server-only module, which ensures that the Prisma client is only generated in the server-side code.

The exported prisma is a global variable that stores the Prisma client instance. If the application is running in production mode, a new Prisma client instance is created. Otherwise, the cached Prisma client instance is used.

Before we can edit our .env file, we need to create a CockroachDB cluster. To get started, follow these steps:

๐Ÿชณ CockroachDB Setup

  1. Head over to the CockroachDB Cloud Console and create a new CockroachDB cluster for free.

For this example, I'll be using the following (default) settings:

CockroachDB Cloud Settings

After creating your cluster, head over to Connect and generate a password for your cluster. Your cluster connection string will be displayed like this:

CockroachDB Cloud Password

Then, copy the connection string and paste it into your .env file like this:

DATABASE_URL="copied connection string goes here"

๐ŸŽจ Example

Now that we have everything set up, let's create a simple application to test our setup. We'll create a simple blog application that allows users to create and read blog posts. To learn more about prisma CRUD operations, check out the official documentation.

First, let's update our schema.prisma file to define our database schema. Open your schema.prisma file and add the following code to it:

model Post {
  id        String   @id @default(cuid())
  title     String
  author    String
  content   String
  createdAt DateTime @default(now())
}
๐Ÿ’ก

model Post is a Prisma model that represents a database table. It has four fields: id, title, author, and content.

Run the following command to create the tables in your database:

npx prisma db push

Now, we have the option to visually explore our database tables using Prisma Studio. To do this, run the following command in your terminal:

npx prisma studio

This command will start the Prisma Studio on port 5555 or http://localhost:5555.


Next, let's create a simple front end for our application.

  1. Create a new folder named components in the src directory of your project or run the following command in your terminal:
mkdir src/components
  1. Create a new file named PostForm.tsx in the components directory and add the following code to it
'use client';
 
import React, { useState } from 'react';
 
const PostForm = () => {
	const [form, setForm] = useState({
		author: '',
		title: '',
		content: '',
	});
	const [loading, setLoading] = useState(false);
 
	const handleForm = async (e: React.FormEvent<HTMLFormElement>) => {
		setLoading(true);
		await fetch('/api', {
			method: 'POST',
			body: JSON.stringify(form),
			headers: {
				'Content-Type': 'application/json',
			},
		}).then((res) => {
			if (res.ok) {
				setLoading(false);
			}
		});
	};
 
	return (
		<form
			onSubmit={(e) => {
				handleForm(e as any);
			}}
			className='flex w-full flex-col space-y-4'
		>
			<input
				type='text'
				className='border-2 bg-transparent p-3'
				placeholder='John Doe'
				onChange={(e) => setForm({ ...form, author: e.target.value })}
				value={form.author}
			/>
			<input
				type='text'
				className='border-2 bg-transparent p-3'
				placeholder='Cool Blog Title'
				onChange={(e) => setForm({ ...form, title: e.target.value })}
				value={form.title}
			/>
			<textarea
				className='resize-none border-2 bg-transparent p-3'
				placeholder='Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
				onChange={(e) => setForm({ ...form, content: e.target.value })}
				value={form.content}
			/>
			<button disabled={loading} className='w-fit'>
				add new
			</button>
		</form>
	);
};
 
export default PostForm;
๐Ÿ’ก

-use client makes this is a client side component since this component's using hooks.

  1. Let's bring the PostForm component to our app/page.tsx file, and let's also fetch the posts from our database.

Open your app/page.tsx file and make the following changes:

import PostForm from '@/components/PostForm';
import { prisma } from '../../lib/db';
 
export default async function Home() {
	const posts = await prisma.post.findMany();
 
	return (
		<main className='flex min-h-screen flex-col items-center space-y-6 p-24'>
			<PostForm />
 
			<div className='flex w-full flex-col space-y-4 divide-y-4 border-4'>
				{posts.map(
					(post) =>
						post.content &&
						post.title && (
							<div
								key={post.id}
								className='flex flex-col space-y-2 bg-green-900 p-3'
							>
								<h2 className='text-2xl font-bold'>
									{post.title}
								</h2>
								<p className='text-sm text-white'>
									{post.content}
								</p>
								<p className='text-xs text-white'>
									{post.author}
								</p>
							</div>
						),
				)}
			</div>
		</main>
	);
}
๐Ÿ’ก

Here, we are only fetching posts that have a content and title. This is to ensure that we don't render any empty posts.

  1. Now, let's create an API route to handle our form submission. First, create an api forlder inside of the app folder or run the following command in your terminal:
mkdir src/app/api
  1. Create a new file named route.ts in the api directory and add the following code to it:
import { NextResponse, NextRequest } from 'next/server';
import { prisma } from '../../../lib/db';
 
export async function POST(request: NextRequest, response: NextResponse) {
	if (request.method === 'POST') {
		try {
			const { title, author, content } = await request.json();
 
			await prisma.post.create({
				data: {
					title,
					author,
					content,
				},
			});
		} catch (error: any) {
			console.error('Error:', error);
			return NextResponse.json({
				status: 500,
				error: error.message,
			});
		}
 
		return NextResponse.json({
			status: 200,
			body: {
				message: 'Success',
			},
		});
	}
}

Through this API route, we are creating a new post in our database using our PostForm component. We are also handling any errors that may occur during the process.

๐Ÿงช Testing

With the setup complete, let's test our application to ensure everything is working as expected.

  1. Start the development server by running the following command in your terminal:
npm run dev
  1. Open your browser and navigate to http://localhost:3000. You should see the following page:
Demo Page
  1. Enter some test details and click the "add new" button. You should see the following changes after submitting the form:
Demo Page Testing

Head over to the Prisma Studio and refresh the page. You should see the new post data in your CockroachDB database:

Prisma Studio

๐ŸŽ‰ You've successfully set up CockroachDB with Next.js 13.