DEV Community

Raphael Chaula
Raphael Chaula

Posted on

Adding MongoDB (Mongoose) to Next.js APIs

After you have created a Next.js app, install mongoose yarn add mongoose then create next.config.js at the root directory of your app if it doesn't exist and in it add your MongoDB connection url string.

next.config.js

module.exports = {
    env: {
        mongodburl: "Your MongoDB connection String",
    }
};
Enter fullscreen mode Exit fullscreen mode

Then create a MongoDB connect middleware that will be called to create a new connection to DB or reuse the existing one whenever we do an operation to DB, in my case I added middleware folder in the root directory of the app and added it there.

middleware/mongodb.js

import mongoose from 'mongoose';

const connectDB = handler => async (req, res) => {
  if (mongoose.connections[0].readyState) {
    // Use current db connection
    return handler(req, res);
  }
  // Use new db connection
  await mongoose.connect(process.env.mongodburl, {
    useUnifiedTopology: true,
    useFindAndModify: false,
    useCreateIndex: true,
    useNewUrlParser: true
  });
  return handler(req, res);
};

export default connectDB;
Enter fullscreen mode Exit fullscreen mode

Then create your models, in my case I added models folder in root directory of the app and created a User model in it.

models/user.js

import mongoose from 'mongoose';
var Schema = mongoose.Schema;

var user = new Schema({
  name: {
    type: String,
    required: true
  },
  email: {
    type: String,
    required: true
  },
  password: {
    type: String,
    required: true
  },
  since: {
    type: Date,
    default: Date.now
  }
});

mongoose.models = {};

var User = mongoose.model('User', user);

export default User;
Enter fullscreen mode Exit fullscreen mode

Then lets create an api for user and add create a new user functionality in it in the pages/api/user directory.

pages/api/user.js

import connectDB from '../../middleware/mongodb';
import bcrypt from '../../middleware/bcrypt';
import User from '../../models/user';

const handler = async (req, res) => {
  if (req.method === 'POST') {
    // Check if name, email or password is provided
    const { name, email, password } = req.body;
    if (name && email && password) {
        try {
          // Hash password to store it in DB
          var passwordhash = await bcrypt.sign(password);
          var user = new User({
            name,
            email,
            password: passwordhash,
          });
          // Create new user
          var usercreated = await user.save();
          return res.status(200).send(usercreated);
        } catch (error) {
          return res.status(500).send(error.message);
        }
      } else {
        res.status(422).send('data_incomplete');
      }
  } else {
    res.status(422).send('req_method_not_supported');
  }
};

export default connectDB(handler);
Enter fullscreen mode Exit fullscreen mode

We are done here, just make a post request to http://localhost:3000/api/user in the request body include: name email and password you will get a response either user object if user is created successfully or an error message if something went wrong.

Happy Hacking!

Discussion (22)

Collapse
nasiruddinsaiyed profile image
Nasiruddin Saiyed • Edited on

Well explained, +1, but it will not work if we are exporting next project into static site using next export. [nextjs.org/docs/api-routes/introdu...]

dev-to-uploads.s3.amazonaws.com/i/...

Collapse
raphaelchaula profile image
Raphael Chaula Author

Yes, API routes only work server side (Lambdas) in Next.js.

Collapse
souvikinator profile image
Souvik Kar Mahapatra • Edited on

On changes in any JS file other than the models gives error: Cannot overwriteUsermodel once compiled. at Mongoose.model next js since during hot reload as there are no changes in the model file so the previously compiled one is used (cached).
In case someone is facing such issue can fix this in following way:

global.User = global.User || mongoose.model("User", userSchema);

export default global.User;
Enter fullscreen mode Exit fullscreen mode
Collapse
bias profile image
Tobias Nickel

nice, thanks, never used next, but wanted to know how APIs are done with it. However I looked some more into the official docunentation.

It loojs very straight forward. 👍

Collapse
raphaelchaula profile image
Raphael Chaula Author

You're welcome.

Collapse
gaddmaster profile image
Daniel Gadd

Hi

Getting errors with getServerSideProps, which is an important example you left out. For a time it worked until recently. When I import a scheme on a page I get a t.version error and others.

Do you know the correct, error free way at importing a scheme on a page for use with getServerSideProps ?

Thanks

Daniel

Collapse
raphaelchaula profile image
Raphael Chaula Author

Hi, can you share the snippet or your code please!
It will be easier for me to understand the issue and help you.

Collapse
gaddmaster profile image
Daniel Gadd

Wow - Didn't see this until now. Playing around and got through it but when it pops up again I'll try make a tiny empty project to show example. I did recently update Node and NextJS so maybe not see again :)

Collapse
regisnut profile image
Regisnut

Hi, can you precise if I host the website on vercel, if mongodb will be on vercel too? or do I need to host it on heroku as an example?
thanks

Collapse
raphaelchaula profile image
Raphael Chaula Author

You can host the website on vercel, it will work just fine, I used MongoDB Atlas, so you can host MongoDB anywhere.

Here is what you should not do;
Don't export the Next.js app, it has to be server side.

Collapse
regisnut profile image
Regisnut

Ouah, nice to hear ! I will use MongoDB atlas too with mongoose.
But I'm still a noob, I don't know what is export a Next.js App?

Thread Thread
raphaelchaula profile image
Raphael Chaula Author

Export is when you want to build a Next.js app into static HTML file.
You can read more about it here nextjs.org/docs/advanced-features/...

Collapse
vicwildcode profile image
vicwildcode

HI, thanks for the tutorial, i have a question, what about connecting 2 different folders, one containing front project, and second containint backend made with Mongodb, mongoose and node? i cannot find this anywhere , thanks if anybody can help with this

Collapse
raphaelchaula profile image
Raphael Chaula Author

Hi, By default next.js supports API routes nextjs.org/docs/api-routes/introdu... you can start with that link, they are inside /pages/api folder.

But you can create your own server (custom) and decide for yourself how you want your directory structure to be here nextjs.org/docs/advanced-features/...

Thanks

Collapse
megens profile image
Robert Megens

Thanks very much. NextJS seemingly rebuilds my User model at each page call, so this line saved me a persistent overwrite warning error:

mongoose.models = {};

Collapse
justicebringer profile image
Gabriel
import mongoose from 'mongoose';
import { BookDocument } from './book.interface';
import { BookSchema } from './book.schema';

export const BookModel = mongoose.models.Book || mongoose.model<BookDocument>('Book', BookSchema);
export default BookModel;
Enter fullscreen mode Exit fullscreen mode

I think this is a better way.

Collapse
raphaelchaula profile image
Raphael Chaula Author

You are welcome.

Collapse
fedecingerle profile image
Federico Cingerle

Hi! do you have a github repo with this explanation? If you have it, could you share it?

Collapse
raphaelchaula profile image
Raphael Chaula Author • Edited on

I don't have any repo specifically to that article but here is a project similar, you can check it out, github.com/raphaelchaula/joinshift... , it is a Next.js project with Mongoose and MongoDB.

Collapse
fedecingerle profile image
Federico Cingerle

Thanks very much!!!!

Collapse
bouananiyasser profile image
BOUANANI YASSER

Very helpful sir, thanks a lot.

Collapse
raphaelchaula profile image
Raphael Chaula Author

You're welcome