Setup CockroachDB with Next.js 13.
NextJS
CockroachDB
SQL
Prisma
TypeScript
ORM
Created @ September 15, 2023 (1y ago)
9 min read
โญ๏ธ 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
- 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
- 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
- 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
- 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:
After creating your cluster, head over to Connect and generate a password for your cluster. Your cluster connection string will be displayed like this:
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.
- Create a new folder named components in the src directory of your project or run the following command in your terminal:
mkdir src/components
- 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.
- Let's bring the
PostForm
component to ourapp/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.
- 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
- 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.
- Start the development server by running the following command in your terminal:
npm run dev
- Open your browser and navigate to
http://localhost:3000
. You should see the following page:
- Enter some test details and click the "add new" button. You should see the following changes after submitting the form:
Head over to the Prisma Studio and refresh the page. You should see the new post data in your CockroachDB database:
๐ You've successfully set up CockroachDB with Next.js 13.