Introduction to Prisma with Next.js
This tutorial outlines how to use Prisma along with Next.js. It assumes a basic understanding of Next.js (which, in turn, assumes basic knowledge of React). By the end of the tutorial, you will have stood up a Prisma client, a development SQLite database, and a Next.js application.
This tutorial will not cover GraphQL with Prisma. If that is something you're interested in, please refer to my live coding video where I add Prisma with GraphQL to a Next.js project.
Create a New Next.js Project
From your terminal, run:
npm init next-app
# or
yarn create next-app
You can find more information about the commands above in the Next.js docs.
This will install a new Next.js project with the directory name that you specified. Run:
npm run dev
# or
yarn dev
to start the development server. Now visit http://localhost:3000 to see your Next.js app. Edit /pages/index. js
to modify this page.
Install Prisma
From your terminal, run:
npm install @prisma/client
npm install @prisma/cli --save-dev
# or
yarn add @prisma/client
yarn add @prisma/cli -D
This installs the Prisma CLI which we can now use to initialize Prisma.
Initialize Prisma
From your terminal, run
npx prisma init
# or
yarn prisma init
This creates two new files: /prisma/.env
and prisma/schema.prisma
.
-
/prisma/.env
- Defines the environment variables used in/schema.prisma
. Learn more here. -
/schema.prisma
- datasource, generator and model definitions are added here. Prisma will use this to generate migrations, GraphQL schemas and TypeScript types. Learn more here.
Add SQLite Database as Datasource
For the purposes of this tutorial, we will use a SQLite database. In /prisma/.env
, change DATABASE_URL
to file:./dev.db
:
# /prisma/.env
DATABASE_URL="file:./dev.db"
and in /prisma/schema.prisma
change the datasource provider to sqlite
:
# prisma/schema.prisma
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
# ... the rest of the file
If you're interested in using postgres
as your database, you can skip this step and, instead, replace DATABASE_URL
with your actual postgres URL.
Add a Data Model
For simplicity's sake, we will create a lightweight data model. In /prisma/schema.prisma
, add the movie model:
# prisma/schema.prisma
# ...stuff at the top of the file
model Movie {
id Int @default(autoincrement()) @id
director String
movieName String
yearReleased Int
}
Generate and Run Database Migrations
With the our model all set up, we're ready to generate migrations that will add these tables to our database. First, run:
npx prisma migrate save --experimental
# or
yarn prisma migrate save --experimental
Since we haven't done so, it will create a SQLite database for you. It will ask for a migration name; this is optional. You can view the newly created migration in the /prisma/migrations
folder. Take a look and you'll see that it generated all the SQL necessary to create the new movies
table.
Note that the new table wasn't created; simply the code to create said table. To create the table, this migration needs to be run. We do this by running:
npx prisma migrate up --experimental
# or
yarn prisma migrate up --experimental
This command will run any migrations that have not yet been run. After this, you can use your favorite database client (I'm partial to TablePlus) to view your database.
Learn more about Prisma migrations here.
Generate the Prisma Client
The Prisma Client is a database client tailored to your database schema. This means that we will easily be able to call a function that runs CRUD operations against our database. In our case, this means the Prisma Client will have a movies
layer with functions to perform all CRUD operations.
To generate the Prisma Client, run:
npx prisma generate
# or
yarn prisma generate
Our Prisma Client is ready for use.
Learn more about the Prisma Client here.
Add a POST endpoint to Create New Movies
Let's use our newly created Prisma Client to create a /movies/
endpoint that creates new movies. In /pages/api/movies.js
(you'll have to create an /api
directory and a movies.js
file), paste the following:
// /pages/api/movies.js
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
export default async function (req, res) {
if (req.method === 'POST') {
const { body } = req;
const movie = await prisma.movie.create({ data: JSON.parse(body) });
res.json(movie);
}
}
Any file inside the folder /pages/api
is mapped to /api/*
and treated as an API endpoint. In our case, we now have an endpoint at http://localhost:3000/api/movies
.
Stepping down the file, we:
- Import the
PrismaClient
from@prisma/client
. Yes, our own personal database client is saved tonode_modules
. The generated code is saved tonode_modules
and is referred to as a "smart node module." You can learn more here. - Initialize an instance of the
PrismaClient
and save it to a variable calledprisma
. - Use a Next.js API Route and only handle POST request.
- Use the
body
of the request and the Prisma client to create a new movie and save it to a variable calledmovie
. Note that we parse the body since we will send it as a JSON string. - Respond with the
movie
created in the step above.
Create a Movie Submission Form
We will use Formik to create our movie submission form. Please feel free to not use Formik if you're more comfortable using HTML forms (or any other React forms library).
If you're using Formik, run:
npm install formik
# or
yarn add formik
Replace all of pages/index.js
with:
// /pages/index.js
import { Field, Formik, Form } from 'formik';
const Home = () => (
<div className="container">
<Formik
initialValues={{
director: '',
movieName: '',
yearReleased: '',
}}
onSubmit={(values) => {
fetch('http://localhost:3000/api/movies', {
method: 'POST',
body: JSON.stringify({ ...values, yearReleased: Number(values.yearReleased) }),
});
}}
>
<Form>
<label>
Movie Name
<Field name="movieName" type="text"></Field>
</label>
<label>
Director
<Field name="director" type="text"></Field>
</label>
<label>
Year Released
<Field name="yearReleased" type="text"></Field>
</label>
<button type="submit">Submit</button>
</Form>
</Formik>
</div>
);
export default Home;
The code above should be straightforward. The submit function makes a POST request to our /api/movies
endpoint. Please note that we need to cast yearReleased
here to a number
as the Prisma client expects an Int
(as defined in /prisma/schema.prisma
.
Now, create a movie and press submit. Using your database client, you can view the movies
table and see that a new movie was created.
Use Server-Side Rendering to Hydrate Page Props on the Server
This right here is where the beauty of Next.js comes in. We can use getServerSideProps
to fetch our movie data on the server-side (using our Prisma Client). The movies will be pre-rendered on our homepage (no client-side fetching necessary!).
Normally, you might create a GET
endpoint that uses the Prisma client to fetch a list of movies and respond with said list of movies. With getServerSideProps
, there's no need for the endpoint. We can use the Prisma client directly in that function to get the list of movies and inject our page's props with the movies.
At the bottom of our /pages/index.js
file, add the following code:
// /pages/index.js
// Home component cut for brevity
export const getServerSideProps = async () => {
const prisma = new PrismaClient();
const movies = await prisma.movie.findMany();
return { props: { movies } };
};
Here, we:
- Instantiate our
PrismaClient
- Get all movies using the
prisma
instance - Return a
props
object that includes themovies
we just fetched
With this code, our Home
component now has movies
props. For example, we can render the movies as follows:
// /pages/index.js
const Home = ({ movies }) => (
<div className="container">
{movies.map((movie) => (
<div key={movie.id}>
<p>Name: {movie.movieName}</p>
<p>Director: {movie.director}</p>
<p>Year Released: {movie.yearReleased}</p>
</div>
))}
<Formik>
{/* your movie form is here; cut for brevity */}
</Formik>
</div>
);
Again, there is NO fetching of movies on the client. It's all done on the server.
Mission Accomplished
This tutorial should be enough to get you started with Next.js and Prisma.
If you have any questions or feedback, you can reach me on Twitter: @aryanjabbari.
Top comments (6)
How to use pg master/slave with prisma?
how to upload file with prisma ?
What if you want to use prisma with multiple endpoints? Do you generate a client for each endpoint, or do you export it and import it in every endpoint?
I'd just generate a Prisma client for each endpoint. If you're using some type of serverless endpoint, I'd generate the Prisma client outside of the called function so only one client is generated (using node's caching).
I know it's been an eternity since you posted this but it really saved me today. Thank you
I love hearing it, Noah! :)