Back to Blog Page
Frontend Development

How to Integrate MongoDB into your Next.js Applications

How to Integrate MongoDB into your Next.js Applications

Written by Kolade Chris | Jul 20, 2024 | #MongoDB #Next.js | 8 minute Read

Integrating MongoDB with a Next.js application is a powerful way to create dynamic, data-driven websites and applications.

This article will guide you through the process of setting up MongoDB (using Mongoose as the ORM) to interact with your database. We’ll use MongoDB Atlas to store our data on the cloud, then display the data in a Next.js application using the app router.

There are several other ways you can achieve this. Chief amongst them is server actions with an ORM like Prisma or Drizzle. This guide will focus on doing things in the good old way we set up an Express application to integrate with a React or HTML/JavaScript project using MongoDB as the database and Mongoose as the ORM.

Before we dive into the process, here are a few things you should already know and have in place:

  • A MongoDB Atlas account
  • Basics of Next.js
  • Basic understanding of mongoose

Set up the MongoDB Atlas Project

Since we’ll fetch the data from a MongoDB Atlas database, let’s set up the database first.

Step 1: Log in to MongoDB Atlas

Log on to mongodb.com and log in to your account, or create an account if you don’t have one.

Step 2: Create an Atlas Project

When you’re in, click on the folder icon on the top-right corner and then the New Project button.

Create MongoDB Project

In the next window, give your project a name and click the Next button

Name MongoDB Project

Click Create Project on the next page and you’ll be prompted to create a cluster.

Step 3: Create a Cluster

A cluster is the server that will store your data. So, you need one.

Click the giant Create button to start the process

Create Cluster

Select the MO free tier, name your cluster, and click the Create Deployment button.

Name Cluster

As your database grows, you might need to upgrade to any of the generous free tier

Step 4: Connect to your Database

After creating your cluster, you’ll be prompted to connect to it. But first, you need to create a database user.

Enter the username and password for the database user and click the Create Database User button.

Create Database User

After that, the Choose a connection method button will turn green, so click it.

Green Connection Button

Select drivers in the next pop-up

After that, make sure Node JS is selected and copy the connection string, then click Done

Copy Connection String

Step 5: Create Database Network Access

By default, the current IP address of your computer will only be able to access the database. You can temporarily allow access from anywhere, and then later change that based on where your app is deployed to.

To do that, select Network Access from the sidebar and click ADD IP ADDRESS

Add IP Address Button Click

In the popup that shows up after that, click ALLOW ACCESS FROM ANYWHERE and Confirm

Allow Access from Everywhere

Step 6: Add Data to your Database

The next thing to do is add the data to query to your database.

Click Database in the sidebar and then Browser Collections

Browse Collections

Select Add My Own Data

Add Your Own Data

You will then be prompted to create a database. Give your database a name (I chose fav-animals), and your collection a name (I chose animals), then click the Create button.

Create Database

When you do that, you’ll be directed to an interface that looks like the one you can see below:

Click the INSERT DOCUMENT button

Remove the existing fields and select the curly braces

Remove Existing Fields

Expand the JSON data below and paste it in:

1
[
2
{
3
"name": "Lion",
4
"scientific_name": "Panthera leo",
5
"male_name": "Lion",
6
"female_name": "Lioness",
7
"offspring_name": "Cub",
8
"description": "Lions are large carnivorous mammals known for
9
their majestic appearance and social structure.",
10
"image": "https://cdn.pixabay.com/photo/2023/08/31/17/57/lion-8225638_640.jpg",
11
"geographic_location": "Sub-Saharan Africa",
12
"litter": "2 - 6",
13
"natural_enemy": "Hyenas",
14
"diet": "Carnivorous",
15
"life_span": 10,
16
"createdAt": "2024-05-06T00:00:00.000Z",
17
"updatedAt": "2024-05-06T00:00:00.000Z"
18
},
138 collapsed lines
19
{
20
"name": "Elephant",
21
"scientific_name": "Loxodonta africana",
22
"male_name": "Bull",
23
"female_name": "Cow",
24
"offspring_name": "Calf",
25
"description": "Elephants are the largest land animals
26
and are known for their long tusks and trunks.",
27
"image": "https://cdn.pixabay.com/photo/2020/01/02/14/53/elephant-4736008_640.jpg",
28
"geographic_location": "Africa, Asia",
29
"litter": "1",
30
"natural_enemy": "Lions",
31
"diet": "Herbivorous",
32
"life_span": 60,
33
"createdAt": "2024-05-06T00:00:00.000Z",
34
"updatedAt": "2024-05-06T00:00:00.000Z"
35
},
36
{
37
"name": "Tiger",
38
"scientific_name": "Panthera tigris",
39
"male_name": "Tiger",
40
"female_name": "Tigress",
41
"offspring_name": "Cub",
42
"description": "Tigers are large carnivorous cats known
43
for their striped fur patterns and powerful hunting abilities.",
44
"image": "https://cdn.pixabay.com/photo/2019/04/25/20/52/amur-tiger-4155922_640.jpg",
45
"geographic_location": "Asia",
46
"litter": "3 - 4",
47
"natural_enemy": "Humans",
48
"diet": "Carnivorous",
49
"life_span": 15,
50
"createdAt": "2024-05-06T00:00:00.000Z",
51
"updatedAt": "2024-05-06T00:00:00.000Z"
52
},
53
{
54
"name": "Giraffe",
55
"scientific_name": "Giraffa camelopardalis",
56
"male_name": "Bull",
57
"female_name": "Cow",
58
"offspring_name": "Calf",
59
"description": "Giraffes are tall, herbivorous mammals
60
known for their long necks and spotted coat patterns.",
61
"image": "https://cdn.pixabay.com/photo/2021/07/01/08/48/giraffe-6378717_640.jpg",
62
"geographic_location": "Africa",
63
"litter": "1",
64
"natural_enemy": "Lions",
65
"diet": "Herbivorous",
66
"life_span": 25,
67
"createdAt": "2024-05-06T00:00:00.000Z",
68
"updatedAt": "2024-05-06T00:00:00.000Z"
69
},
70
{
71
"name": "Wolf",
72
"scientific_name": "Canis lupus",
73
"male_name": "Wolf",
74
"female_name": "She-wolf",
75
"offspring_name": "Pup",
76
"description": "Wolves are social carnivores known for
77
their pack structure and howling communication.",
78
"image": "https://cdn.pixabay.com/photo/2020/06/21/14/20/wolf-5325060_640.jpg",
79
"geographic_location": "North America, Europe, Asia",
80
"litter": "4 - 6",
81
"natural_enemy": "Humans",
82
"diet": "Carnivorous",
83
"life_span": 12,
84
"createdAt": "2024-05-06T00:00:00.000Z",
85
"updatedAt": "2024-05-06T00:00:00.000Z"
86
},
87
{
88
"name": "Penguin",
89
"scientific_name": "Spheniscidae",
90
"male_name": "Penguin",
91
"female_name": "Penguin",
92
"offspring_name": "Chick",
93
"description": "Penguins are flightless birds adapted
94
for life in the water, known for their tuxedo-like appearance.",
95
"image": "https://cdn.pixabay.com/photo/2022/04/03/08/37/birds-7108368_640.jpg",
96
"geographic_location": "Antarctica, South America, Africa, Australia",
97
"litter": "2",
98
"natural_enemy": "Seals, sea lions",
99
"diet": "Carnivorous (fish, krill)",
100
"life_span": 20,
101
"createdAt": "2024-05-06T00:00:00.000Z",
102
"updatedAt": "2024-05-06T00:00:00.000Z"
103
},
104
{
105
"name": "Dolphin",
106
"scientific_name": "Delphinidae",
107
"male_name": "Bull",
108
"female_name": "Cow",
109
"offspring_name": "Calf",
110
"description": "Dolphins are highly intelligent marine mammals
111
known for their playful behavior and communication skills.",
112
"image": "https://cdn.pixabay.com/photo/2017/08/29/01/13/dolphin-2691864_640.jpg",
113
"geographic_location": "Oceans worldwide",
114
"litter": "1",
115
"natural_enemy": "Sharks, killer whales",
116
"diet": "Carnivorous (fish, squid)",
117
"life_span": 30,
118
"createdAt": "2024-05-06T00:00:00.000Z",
119
"updatedAt": "2024-05-06T00:00:00.000Z"
120
},
121
{
122
"name": "Kangaroo",
123
"scientific_name": "Macropodidae",
124
"male_name": "Boomer",
125
"female_name": "Flyer",
126
"offspring_name": "Joey",
127
"description": "Kangaroos are marsupials known for their powerful
128
hind legs and pouches, where they carry their young.",
129
"image": "https://cdn.pixabay.com/photo/2021/09/08/02/23/kangaroo-6605269_640.jpg",
130
"geographic_location": "Australia",
131
"litter": "1",
132
"natural_enemy": "Dingoes",
133
"diet": "Herbivorous",
134
"life_span": 20,
135
"createdAt": "2024-05-06T00:00:00.000Z",
136
"updatedAt": "2024-05-06T00:00:00.000Z"
137
},
138
139
{
140
"name": "Owl",
141
"scientific_name": "Strigiformes",
142
"male_name": "Owl",
143
"female_name": "Owl",
144
"offspring_name": "Owlet",
145
"description": "Owls are nocturnal birds of prey known for
146
their silent flight and keen hunting abilities.",
147
"image": "https://cdn.pixabay.com/photo/2021/12/21/08/29/owl-6884773_640.jpg",
148
"geographic_location": "Worldwide",
149
"litter": "3",
150
"natural_enemy": "Large birds of prey",
151
"diet": "Carnivorous (small mammals, birds, insects)",
152
"life_span": 10,
153
"createdAt": "2024-05-06T00:00:00.000Z",
154
"updatedAt": "2024-05-06T00:00:00.000Z"
155
},
156
{
157
"name": "Crocodile",
158
"scientific_name": "Crocodylidae",
159
"male_name": "Bull",
160
"female_name": "Cow",
161
"offspring_name": "Hatchling",
162
"description": "Crocodiles are large reptiles known for their
163
powerful jaws and semi-aquatic lifestyle.",
164
"image": "https://cdn.pixabay.com/photo/2024/04/21/14/14/crocodile-8710743_640.jpg",
165
"geographic_location": "Africa, Asia, Americas, Australia",
166
"litter": "12 - 48",
167
"natural_enemy": "Other crocodiles, large predators",
168
"diet": "Carnivorous",
169
"life_span": 70,
170
"createdAt": "2024-05-06T00:00:00.000Z",
171
"updatedAt": "2024-05-06T00:00:00.000Z"
172
}
173
]

Afer you’ve pasted in the data, if any of the values are greyish, it means there are errors. Make sure all the values are green and you’ll be good to go.

Click Insert

Insert Data

Install Next.js to Start Setting Up MongoDB in a Next.js App

Now that you’re done with setting up MongoDB Atlas and filling the database with data, the next thing is to install Next.js.

Create a folder and open it with VS Code, then open the integrated terminal and run the command below:

Terminal window
1
npx create-next-app@latest

The installation wizard will ask you a few questions. Here are the choices I made:

Next.js Installation Prompts

When the installation is done, run npm run dev to start the local dev server of the application.

Install MongoDB and Mongoose Packages

We need the Mongoose ORM and MongoDB library to effectively connect to our database and set up both our model and route. So in the terminal again, run the command below:

Terminal window
1
npm install mongodb mongoose

Create Database Connection File

Create a config folder in the root. Inside the folder, create a database.ts file and paste the following in it:

1
import mongoose from 'mongoose';
2
3
const connectDB = async (): Promise<void> => {
4
try {
5
await mongoose.connect(process.env.MONGODB_CONNECTION_URI as string);
6
7
console.log('MongoDB connected successfully');
8
} catch (error) {
9
console.log('Error connecting to database...', error);
10
}
11
};
12
13
export default connectDB;

What goes in the mongoose.connect() method is the connection string you copied in step 4.

So, create a .env file in the root, create a MONGODB_CONNECTION_URI variabel and assign the connection string to it. Make sure you replace the password with your database user password.

Also, enter the name of your database as the database to use. Otherwise, MongoDB will automatically create a test database for you.

The MONGODB_CONNECTION_URI variable should look like this:

Mongo URI

To quickly test the connection, go to page.tsx inside the app folder. Inside the file, import the database connection file the log it to the console by invoking it:

1
import connectDB from '@/config/database';
2
console.log(connectDB());

If you see the text MongoDB connected successfully (or any console message you entered in the database connection file) in the console, then everything is working fine. Otherwise, look at the error message to figure out what could have gone wrong.

On many occasions, the connection can fail because of a wrong username and password. So make sure both are correctly entered.

Create the Database Model

The next thing is to create a model for the database. This model will define what we expect to get from the database, what we have to insert, and what we need to update. It’s like a validation for what we want in the database.

Create a models folder in the root and an Animal.ts file in it. After that, import Schema, model, models, and Document all from mongoose and define the types for the fields:

1
import { Schema, model, models, Document } from 'mongoose';
2
3
interface IAnimal extends Document {
4
name: string;
5
scientific_name: string;
6
male_name: string;
7
female_name: string;
8
offspring_name: string;
9
description: string;
10
geographic_location: string;
11
litter: string;
12
natural_enemy: string;
13
diet: string;
14
life_span: number;
15
}

After that, define the schema corresponding to the interface. Expand the code below to see the full schema:

1
import { Schema, model, models, Document } from 'mongoose';
2
3
interface IAnimal extends Document {
4
name: string;
5
scientific_name: string;
6
male_name: string;
7
female_name: string;
8
offspring_name: string;
9
description: string;
10
geographic_location: string;
11
litter: string;
12
natural_enemy: string;
13
diet: string;
14
life_span: number;
15
}
16
53 collapsed lines
17
const AnimalSchema = new Schema<IAnimal>(
18
{
19
name: {
20
type: String,
21
required: true,
22
},
23
scientific_name: {
24
type: String,
25
required: true,
26
},
27
male_name: {
28
type: String,
29
required: true,
30
},
31
female_name: {
32
type: String,
33
required: true,
34
},
35
offspring_name: {
36
type: String,
37
required: true,
38
},
39
description: {
40
type: String,
41
required: true,
42
},
43
geographic_location: {
44
type: String,
45
required: true,
46
},
47
litter: {
48
type: String,
49
required: true,
50
},
51
natural_enemy: {
52
type: String,
53
required: true,
54
},
55
diet: {
56
type: String,
57
required: true,
58
},
59
life_span: {
60
type: Number,
61
required: true,
62
},
63
},
64
{}
65
);
66
67
const Animal = models.Animal || model<IAnimal>('Animal', AnimalSchema);
68
69
export default Animal;

Create the API Route to Query the Data

Inside the app directory, create an api folder, then an animal folder, and then a route.ts file.

Inside that route.ts file, paste the following:

1
import connectDB from '@/config/database';
2
import Animal from '@/models/Animal';
3
4
export const GET = async (request: Request): Promise<Response> => {
5
try {
6
await connectDB();
7
8
const animals = await Animal.find({});
9
return new Response(JSON.stringify(animals), {
10
status: 200,
11
});
12
} catch (error) {
13
return new Response(`Something went wrong: ${error}`, { status: 500 });
14
}
15
};

Query the Data

To finally query the data, head over to the page.jsx file and fetch the data from your local api route.

You can’t use a useState or useEffect hook to fetch data in a server component, so you can do the fetching directly:

1
import Image from 'next/image';
2
3
// import connectDB from '@/config/database';
4
// console.log(connectDB());
5
6
const fetchAnimals = async () => {
7
try {
8
const res = await fetch('http://localhost:3001/api/animals');
9
const animalRes = await res.json();
10
11
if (!res.ok) {
12
throw new Error('Failed to fetch data');
13
}
14
return animalRes;
15
} catch (error) {
16
console.log(error);
17
}
18
};
19
20
export default async function Home() {
21
const favAnimals = await fetchAnimals();
22
console.log(favAnimals);
23
return <main>{/*page content*/}</main>;
24
}

Subscribe to my newsletter for coding tips, videos from reputable sources, articles from OG tech authors, and a ton of other goodies.

No BS. No fluff. Just pure software development goodies on a Sunday every week.

Display the Data (Animals)

Finally, you can map through the favAnimals data and render them on the page. Expand the code below to see how I did it and styled the elements with Tailwind CSS:

1
import Image from 'next/image';
2
3
// import connectDB from '@/config/database';
4
// console.log(connectDB());
5
6
const fetchAnimals = async () => {
7
try {
8
const res = await fetch('http://localhost:3001/api/animals');
9
const animalRes = await res.json();
10
11
if (!res.ok) {
12
throw new Error('Failed to fetch data');
13
}
14
return animalRes;
15
} catch (error) {
16
console.log(error);
17
}
18
};
19
70 collapsed lines
20
export default async function Home() {
21
const favAnimals = await fetchAnimals();
22
// console.log(favAnimals);
23
return (
24
<main>
25
<h1 className="text-center text-5xl mt-6">My Favorite Animals</h1>
26
<div className="max-w-7xl mx-auto bg-[url('/wood-texture.jpg')] bg-cover p-8">
27
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
28
{favAnimals.map((animal: any) => (
29
<div
30
key={animal._id}
31
className="bg-white bg-opacity-90 rounded-lg shadow-md overflow-hidden"
32
>
33
<div className="relative h-64">
34
<Image
35
src={animal.image}
36
width={400}
37
height={0}
38
alt={animal.name}
39
/>
40
</div>
41
<div className="p-4 mt-4">
42
<h3 className=" font-extrabold text-2xl mb-2 text-green-500">
43
{animal.name}
44
</h3>
45
<p className="text-gray-700 mb-2">
46
<span className="font-semibold">Description:</span>{' '}
47
{animal.description}
48
</p>
49
<p className="text-gray-700 mb-2">
50
<span className="font-semibold">Male Name:</span>{' '}
51
{animal.male_name}
52
</p>
53
<p className="text-gray-700 mb-2">
54
<span className="font-semibold">Female Name:</span>{' '}
55
{animal.female_name}
56
</p>
57
<p className="text-gray-700 mb-2">
58
<span className="font-semibold">Offspring Name:</span>{' '}
59
{animal.offspring_name}
60
</p>
61
<p className="text-gray-700 mb-2">
62
<span className="font-semibold">Litter:</span> {animal.litter}
63
</p>
64
<p className="text-gray-700 mb-2">
65
<span className="font-semibold">Natural Enemy:</span>{' '}
66
{animal.natural_enemy}
67
</p>
68
<p className="text-gray-700 mb-2">
69
<span className="font-semibold">Trophic Level:</span>{' '}
70
{animal.diet}
71
</p>
72
<p className="text-gray-700 mb-2">
73
<span className="font-semibold">Life Span:</span>
74
{animal.life_span} years
75
</p>
76
<p className="text-gray-700 mb-2">
77
<span className="font-semibold">
78
Geographic Distribution:
79
</span>{' '}
80
{animal.geographic_location}
81
</p>
82
</div>
83
</div>
84
))}
85
</div>
86
</div>
87
</main>
88
);
89
}

If you try to see what’s going on in the browser, you’ll see this error:

Next.js Invalid src prop error

To fix the error, add this to the nextConfig object inside the next.config.mjs file in the root:

1
images: {
2
remotePatterns: [
3
{
4
protocol: 'https',
5
hostname: 'cdn.pixabay.com',
6
},
7
],
8
},

Now you should see the animals rendered in the browser: Animals View

You can grab the full code in the project GitHub repo.

Wrapping Up

I hope you’ve learned enough to be able to integrate MongoDB into your Next.js app using Mongoose as the ORM.

You can take this further by defining a POST, PUT, and DELETE route in the api/animals folder to see how those work too.

If you don’t want to miss out on articles like this, consider subscribing to my newsletter.