Setup Nextjs 14 with MongoDB and Mongoose
In this blog, we will learn how to set up a Next.js 14 project with MongoDB and Mongoose. Setting up Nextjs with MongoDB can be tricky. But I will show you how to do that.
Setup database
I will use MongoDB Atlas for this tutorial. You can use any other MongoDB service or install it locally.
Go to MongoDB Atlas and create an account.
Create a organization if you haven't created any and a project.
Create a cluster and choose the free tier.
Create a database user and add the IP address to the IP access list.
Create a database and a collection. Let's call both of them
posts
Now we have a database and a collection.Get the connection string from the cluster and save it for later.
- Go to overview button on sidebar. And then use connection method.
- Choose correct driver(nodejs latest)
- Copy the connection string
You can also checkout the video tutorial to get a better understanding.
Create a Next.js project
Use the command below to create a new Next.js project. Make sure to use app router.
1npx create-next-app nextjs-mongodb
Install dependencies
Install the mongoose
package.
1npm install mongoose
Connect to database
Create a new .env.local
file and add the connection string to it.
1MONGO_URI=your_connection_string23# Example4MONGO_URI=mongodb+srv://anjan:anjan@cluster0.est6lzg.mongodb.net/posts?retryWrites=true&w=majority
Replace <password>
with database password. And add db name after mongodb.net/
and before ?
. Check the example above.
Create a new file db.js
and add the code below.
1// /src/app/lib/db.js23import mongoose from 'mongoose'45const MONGODB_URI = process.env.MONGO_URI67if (!MONGODB_URI) {8 throw new Error(9 'Please define the MONGODB_URI environment variable inside .env.local',10 )11}1213let cached = global.mongoose1415if (!cached) {16 cached = global.mongoose = { conn: null, promise: null }17}1819async function dbConnect() {20 if (cached.conn) {21 return cached.conn22 }23 if (!cached.promise) {24 const opts = {25 bufferCommands: false,26 }27 cached.promise = mongoose.connect(MONGODB_URI, opts).then(mongoose => {28 console.log('Db connected')29 return mongoose30 })31 }32 try {33 cached.conn = await cached.promise34 } catch (e) {35 cached.promise = null36 throw e37 }3839 return cached.conn40}4142export default dbConnect
Explanation:
- With this
dbConnect
function, we are connecting to the database and caching the connection. - We are only connecting to the database once and reusing the connection. You don't want to connect to the database multiple times.
Where to use dbConnect
function?
This is a tricky question. In basic Node.js projects, you can connect to the database in the entry file index.js
and you don't call that again.
But in Nextjs, there isn't any entry file. Because all the pages and route handlers are specific to the pages or API routes.
But now you can use the experimental feature called instrumentation
. It will allow you to execute any startup script and this runs only once when the nextjs server starts.
Enable the instrumentation
feature by adding the code below to the next.config.js
file.
1module.exports = {2 experimental: {3 instrumentationHook: true,4 },5}
Create a new file instrumentation.js
at the root of project or inside src
directory if it exist. And add the code below.
1import connect from '@/lib/db'23export async function register() {4 await connect()5}
You just need to export the register
function and call the dbConnect
function inside it.
If the connection is successful, you will see the message Db connected
in the console even before you access any page or api route.
What if you don't want to use instrumentation
?
In that case, you have to call the dbConnect
function on every page or api route where you want to access the database.
Because if you try to access the page and you don't call the connection function, you will get an error.
For example, you only call the function in the /home/page.js
file but the first user visiting the /about/page.js
file will get an error. Because the connection is not established yet.
Once you have a connection, you can create model to interact with the database.
Create a model
Create a new file post.js
and add the code below.
1import mongoose from 'mongoose'23const postSchema = new mongoose.Schema({4 title: {5 type: String,6 required: true,7 },8 description: {9 type: String,10 required: true,11 },12})1314export default mongoose.models.Post || mongoose.model('Post', postSchema)
Explanation:
- We create a new schema with
title
anddescription
fields. - We export the model. If the model already exists, we use that. Otherwise, we create a new model.
Add new post
Let's create a form and a server action
1export default async function Home() {2 return (3 <form action={addPost}>4 <div>5 <label>Title</label>6 <input name='title' type='text' />7 </div>8 <div>9 <label>Description</label>10 <textarea name='description' />11 </div>12 <button>Submit</button>13 </form>14 )15}
Create a server action in a separate file.
1'use server'23import Post from '@/models/Post'45const addPost = async post => {6 const title = post.get('title')7 const description = post.get('description')89 const newPost = new Post({ title, description })10 return newPost.save()11}1213export { addPost }
Explanation:
- We have a server action that will add a new post to the database.
- It will be called when the form is submitted.
Get all post
Let's create another function:
1const getPosts = async () => {2 return Post.find()3}
Render the posts.
1import { getPosts } from '@/actions/action'23export default async function Home() {4 const posts = await getPosts()56 return (7 <div>8 {posts.map(post => (9 <div key={post._id}>10 <h1>{post.title}</h1>11 <p>{post.description}</p>12 </div>13 }14 <form action={addPost}>15 <div>16 <label>Title</label>17 <input name='title' type='text' />18 </div>19 <div>20 <label>Description</label>21 <textarea name='description' />22 </div>23 <button>Submit</button>24 </form>25 </div>26 )27}
Now you should get the list of posts from the database.
That's it. You have successfully set up a Next.js 14 project with MongoDB and Mongoose.
Shameless Plug
I have made an Xbox landing page clone with React and Styled components. I hope you will enjoy it. Please consider like this video and subscribe to my channel.
That's it for this blog. I have tried to explain things simply. If you get stuck, you can ask me questions.
Contacts
- Email: thatanjan@gmail.com
- LinkedIn: @thatanjan
- Portfolio: anjan
- Github: @thatanjan
- Instagram : @thatanjan
- Twitter: @thatanjan
Blogs you might want to read:
- Eslint, prettier setup with TypeScript and react
- What is Client-Side Rendering?
- What is Server Side Rendering?
- Everything you need to know about tree data structure
- 13 reasons why you should use Nextjs
- Beginners guide to quantum computers
Videos might you might want to watch: