Learn how to build a fullstack app with Next.js, Prisma, and MongoDB. Explore API routes, advanced Prisma queries, filtering, pagination, and sorting.
Amal
Created: September 11, 2024
Updated: September 18, 2024
Our mission is to make the Internet a safer place, and the new login standard passkeys provides a superior solution to achieve that. That's why we want to help you understand passkeys and its characteristics better.
Building professional web applications can be quite challenging, especially when managing the front-end, back-end, and database interactions. Next.js and Prisma have emerged as two popular tools that simplify this process, allowing developers to focus more on building features rather than worrying about the infrastructure.
Next.js is a framework based on React. Itβs ideal for fullstack applications, providing all the tools needed to create both the frontend and backend in one framework. On the other hand, Prisma is a next-generation Object Relational Mapper (ORM) designed to streamline database access and management. Combining Next.js and Prisma brings simplicity, speed, and scalability.
In this guide, weβll explore why developers increasingly choose Prisma and Next.js, and how you can use them to build a performant fullstack web app.
By the end of this blog, you'll have answers to the following key questions:
How to set up a Next.js project using Prisma as the ORM?
How to implement API Routes and using Prisma with MongoDB in a Next.js app?
What are Prismaβs advanced querying capabilities?
An ORM acts as a bridge between your application and the database, allowing you to work with database records using code instead of raw queries. By translating database tables into objects and simplifying data retrieval, ORMs like Prisma help developers focus on building application features rather than writing complex queries.
The benefits of using an ORM include:
Simplified database interactions: No need for complex queries.
Improved code readability and maintainability: Work with familiar object structures.
Portability: Easily switch between databases without major code changes.
Subscribe to our Passkeys Substack for the latest news, insights and strategies.
SubscribePrisma is an open-source Node.js and TypeScript ORM that simplifies database interactions for developers working with JavaScript and TypeScript.
It allows you to define your database schema in TypeScript, and it supports multiple databases such as MongoDB, PostgreSQL, MySQL, and many more. It automates the generation of queries and migrations, making database management easier for developers.
Become part of our Passkeys Community for updates and support.
JoinThese are the main features of Prisma:
Type Safety for Database Queries: Prisma ensures that your database queries are fully type safe, reducing potential errors.
Auto-generation of Queries: Prisma generates queries automatically based on the models you define. This means there is no need to manually write query logic for common tasks like fetching, updating, or deleting data.
Auto-generation of TypeScript Types: Prisma automatically generates TypeScript types based on your database schema, making it easy to work with strongly typed data throughout your application.
Multi-database Support: Prisma supports a variety of databases, including MongoDB, PostgreSQL, and more, giving you the flexibility to work with the database of your choice.
Migrations: Prisma simplifies database schema changes with easy-to-use migrations, allowing you to evolve your database schema as your project grows.
Prisma stands out among popular ORMs like TypeORM and Drizzle ORM for:
its strong focus on type safety
developer experience
automatic query generation
Unlike TypeORM, which requires more manual handling for complex queries, and Drizzle ORM, which is lightweight but lacks some of Prismaβs tooling, Prismaβs intuitive syntax, TypeScript support, and tools like Prisma Studio enhance the development experience by offering an interface to explore and manipulate the data with a simple command.
Prisma and Next.js combined form an efficient and developer-friendly full-stack solution. Prisma simplifies database management with type-safe queries, integrating seamlessly with Next.jsβ TypeScript-first approach. Together, they enable smooth development by leveraging Next.js for both frontend and backend, while Prisma handles database access. This makes building full-stack applications with server-side rendering and secure database operations more reliable.
Are your users passkey-ready?
Test Passkey-ReadinessIn this section, weβll walk you through building a user management app using Next.js, Prisma, and MongoDB. This step-by-step guide will show you how to integrate Prisma for database management and create API routes to demonstrate Prismaβs ORM capabilities. The app will feature a form for adding new users and display a list of existing users, providing a hands-on example of fullstack development.
This tutorial assumes you are familiar with Next.js, TypeScript, Prisma, and Docker. Moreover, you need Node, NPM, and Docker installed on your machine.
Check System Requirements: Ensure your system meets Docker's minimum requirements (OS version, RAM, CPU, etc.).
Download Docker Desktop: Visit the Docker Desktop website and download the installer for your operating system.
Install Docker Desktop: Run the installer file you downloaded and follow the installation instructions presented by the setup wizard.
Start Docker Desktop: Launch Docker Desktop, and it will start running in the background.
Verify Installation: Open your terminal and run the following command to check if Docker is installed correctly:
Let's explore the structure of our repository full Nextjs & Prisma GitHub repository.
. βββ app β βββ api β β βββ createUser β β β βββ route.ts β β βββ getListUsers β β βββ route.ts β βββ layout.tsx β βββ page.tsx βββ node_modules βββ prisma β βββ schema.prisma βββ .env βββ docker-compose.yml βββ Dockerfile βββ package.json βββ README.md
Here's a brief explanation of the relevant files and directories:
app/
: Contains the Next.js application logic, including the API routes for user management.
api/
: This directory holds the API routes:
createUser/route.ts
: Handles the POST request to add a new user to the database using Prisma.
getListUsers/route.ts
: Handles the GET request to retrieve the list of users from the MongoDB database via Prisma.
prisma/
: Includes the Prisma schema for managing database models.
schema.prisma
: This file defines the Prisma schema, where you set up models and the database connection. In this case, it configures Prisma to work with MongoDB and defines the User model.docker-compose.yml
: Configuration for running the app and database services using Docker.
Dockerfile
: Instructions for building the Next.js application container.
Want to find out how many people can use passkeys?
View Adoption DataFirst, we need to create a Next.js project using this command
Next, we need to install Prisma using the following command:
Want to experiment with passkey flows? Try our Passkeys Debugger.
Try for FreeNow, you need to initialize Prisma in your project using this command:
This will create a prisma/
directory with a schema.prisma
file and an . env
file and also will guide you through the next steps.
In the containerized environment, the MongoDB service runs in a Docker container named mongodb
. Therefore, the DATABASE_URL
is updated to reflect that MongoDB is accessible at mongodb:27017
inside the Docker network.
This environment variable is defined in the docker-compose.yml
file:
We need also to connect Prisma to our database. We can do this by editing the schema.prisma
file and adding the following code:
In Prisma, a model represents a collection in your database (for MongoDB, this means a collection, and for relational databases, it's a table). Prisma uses these models to automatically generate the underlying database schema and provides a way to interact with the data using the Prisma Client.
We can create a model, by adding the following code to the schema.prisma
file. This defines a simple User
model with id
, name
, and email
fields which will be mapped to a MongoDB collection named User. Each instance of this model represents a document inside that collection.
id String @id @default(auto()) @map("_id") @db.ObjectId
: This is the primary identifier for each document in the collection. Every model in Prisma must have an id
field that uniquely identifies each record.
String
: The data type of the id field is String. For MongoDB, this field will hold the ObjectId.
@id
: This annotation tells Prisma that this field is the primary key.
@default(auto())
: This specifies that the id
should be automatically generated by Prisma. In MongoDB, the default for the _id
field is an ObjectId which is automatically generated by the database.
@map("_id")
: MongoDB uses the _id
field as the primary key by default. The @map("_id")
directive tells Prisma to map the id field in the Prisma model to the MongoDB _id
field. This way, Prisma knows that the id
field in the model corresponds to _id
in the database.
@db.ObjectId
: This indicates that in MongoDB, the id
field is of the ObjectId type. Although Prisma uses the String type, it understands that the underlying database will use MongoDB's ObjectId.
name String
: This defines a name
field of type String. It is a simple field where each user can have a name. Prisma automatically maps this field to a field in the MongoDB collection.
email String @unique
: This defines an email
field, also of type String. It represents the user's email address.
@unique
: This directive ensures that the email field is unique across all documents in the collection. Prisma enforces this uniqueness constraint when inserting or updating documents.Prisma offers a client that allows seamless interaction with the database. You can generate this client by running the following command:
In this section, we create two API routes to interact with our MongoDB database via Prisma. These routes will allow fetching and creating users.
This API route retrieves a list of all users from the database using the Prisma method findMany()
. If the DATABASE_URL
is not set, it returns a 500 error. If the request is successful, it returns a JSON array of users.
This API route allows adding a new user using the Prisma create()
method by sending a POST request with name
and email
. It validates the request and saves the user to the database.
Now, we create a basic component that interacts with the APIs. It provides a form to add new users and displays the list of existing users.
This component uses React hooks (useState
, useEffect
) to manage user state. It fetches the list of users from the API and updates the UI when a new user is added via a form.
This user management application uses two Docker containers. The first container runs MongoDB serving as the database for user data. It stores persistent data in a mounted volume and is configured to run with a Replica Set (Prisma requirement). The second container hosts the Next.js application, which connects to MongoDB through an internal network. This container handles the app's logic, rendering the frontend, and managing API requests. Both containers are connected via a shared Docker network, ensuring smooth communication between the app and the database.
To start the MongoDB and Next.js containers, run the following command:
This will build and start both the MongoDB container on port 27017 and the Next.js app on port 3000. Also, it will generate the Prisma Client inside the app container.
Once the containers are running, you must initialize the MongoDB Replica Set. In a new terminal, run these commands:
Now you need to initiate the Replica Set by running the following command inside the MongoDB shell:
You can verify the Replica Set status
After initializing the MongoDB Replica Set, you can access the Next.js app in your browser at: http://localhost:3000
Prisma offers flexible query capabilities, making it easy to implement features like filtering, pagination, and sorting in your Next.js applications. Let's explore some of these advanced features.
Filtering allows you to retrieve only specific records from the database based on certain conditions. Prisma provides an easy way to add filters to your queries using the where
clause.
In this example, users whose names contain the search query are returned. You can customize the filtering logic to match exact names, case-insensitive strings, or even other fields.
Pagination is important when dealing with large datasets, allowing you to load results in chunks. Prisma makes pagination easy using the skip
and take
options.
In this example, users are returned in batches of 10. You can adjust the pageSize
to control how many users are returned per page, and the page parameter to specify which page of results to return.
Hereβs how you can implement pagination to retrieve users in batches:
Sorting helps you order your data based on specific fields (e.g., name, email, created date). Prisma allows you to easily sort results using the orderBy
option.
This code returns users sorted alphabetically by their names in ascending order.
Combining Next.js and Prisma creates an efficient stack for building full-stack web applications. Prisma simplifies the complexities of database management, offering a type-safe and intuitive way to interact with databases like MongoDB, while Next.js provides the perfect framework for building scalable, server-side rendered, and API-driven applications. By using advanced Prisma features like filtering, pagination, and sorting, you can enhance your application's functionality and improve user experience.
Here are some valuable resources:
Table of Contents
Enjoyed this read?
π€ Join our Passkeys Community
Share passkeys implementation tips and get support to free the world from passwords.
π Subscribe to Substack
Get the latest news, strategies, and insights about passkeys sent straight to your inbox.
We provide UI components, SDKs and guides to help you add passkeys to your app in <1 hour
Start for free
Recent Articles