One of the major reasons for the mongoose 5 release was the MongoDB driver removing support for the authenticate() function. Up until Mongoose 4.11, that function was the only way mongoose supported doing authentication. In Mongoose 4.11.0, we added the annoying but necessary useMongoClient deprecation warning, and in mongoose 5.0.0-rc0 we deleted 686 lines of legacy connection logic that removed the need for the useMongoClient option. In addition, we made a couple related improvements to the connection API that will make mongoose much cleaner to work with: we made mongoose.connect() always return a promise, and we added a global and connection-level bufferCommands option.

Consistently Return a Promise for mongoose.connect()

Here's a thought exercise for you: what happens when JavaScript promise resolves to itself?

const promise = new Promise (resolve => { setImmediate(() => resolve(promise)); });

If you said "infinite recursion", you're right. Newer versions of Node.js actually catch chaining cycles like this and print a handy error:

TypeError: Chaining cycle detected for promise #<Promise>

We previously made connect() return a promise in mongoose 4.4.0, but quickly realized this was a backwards breaking change because people relied on the fact that mongoose.connect() returned the mongoose singleton and fixed it in 4.4.1. But then, we also found that people also created promise wrappers around mongoose.connect() that relied on mongoose.connect() returning the mongoose singleton. So, in order to support mongoose.connect() returning something that was promise-like but also looked like mongoose we created the MongooseThenable class, which wrapped the mongoose singleton but also had a .then() and .catch() and resolved to the original mongoose singleton.

In mongoose 5, we cleaned up this spaghetti and made mongoose.connect() return a promise that resolves to the mongoose singleton.

const mongoose = require ( 'mongoose' ); mongoose.connect( 'mongodb://localhost:27017/test' ).then(res => console .log(res));

This means you can no longer chain .on() or .model() onto mongoose.connect() :

mongoose.connect( 'mongodb://localhost:27017/test' ).connection. on( 'error' , handleErr). model( 'Test' , new Schema({ name: String })); mongoose.connect( 'mongodb://localhost:27017/test' ).catch(handleErr); mongoose.connect( 'mongodb://localhost:27017/test' ); mongoose.connection.on( 'error' , handleErr); mongoose.model( 'Test' , new Schema({ name: String }));

This also means mongoose.connect() now works nicely with async/await:

const ret = await mongoose.connect( 'mongodb://localhost:27017/test' ); ret === mongoose;

As for mongoose.createConnection() , mongoose still supports using the return value of mongoose.createConnection() as either a promise or as a connection.

mongoose.createConnection().then(conn => conn.model( 'Test' , schema)); const conn = mongoose.createConnection(); conn.model( 'Test' , schema);

Mongoose does this by deleting conn.then() before resolving the promise, so if you try to call .then() after the connection has successfully connected, you will get an error:

const conn = mongoose.createConnection(); conn.then(() => { console .log(conn.then); });

We don't believe this to be a major limitation, because await doesn't throw an error if .then() is not present. Please open up an issue on GitHub if this causes problems for you.

const conn = mongoose.createConnection(); console .log(conn.then); console .log( await conn); console .log(conn.then); console .log( await conn);

Global and Connection-Level bufferCommands

Mongoose schemas have a bufferCommands option that disables mongoose buffering, which is the mechanism that queues up operations until connection is established.

const mongoose = require ( 'mongoose' ); mongoose.connect( 'mongodb://localhost:27017/test' ); const schema = new mongoose.Schema({ name: String }); const User = mongoose.model( 'User' , schema); User.create({ name: 'Val' }).then(doc => console .log(doc));

In mongoose 4, you had to disable bufferCommands at the schema level, as well as disable the MongoDB driver's buffering mechanism by setting bufferMaxEntries at the connection level:

const mongoose = require ( 'mongoose' ); mongoose.connect( 'mongodb://localhost:27017/test' , { bufferMaxEntries: 0 }); const schema = new mongoose.Schema({ name: String }, { bufferCommands: false }); const User = mongoose.model( 'User' , schema); User.create({ name: 'Val' }).then(doc => console .log(doc));

Disabling buffering is important if you want to report an error immediately if you try to execute an operation when mongoose is disconnected because the MongoDB server is down. However, setting it on the schema level is inconvenient. In mongoose 5, you can set it on the individual connection:

mongoose.connect( 'mongodb://localhost:27017/test' , { bufferMaxEntries: 0 , bufferCommands: false });

You can also globally disable buffering.

mongoose.set( 'bufferCommands' , false ); mongoose.connect( 'mongodb://localhost:27017/test' , { bufferMaxEntries: 0 });

Keep in mind that the connection-level bufferCommands option overrides the global bufferCommands option, and schema-level bufferCommands overrides both.

mongoose.set( 'bufferCommands' , false ); mongoose.connect( 'mongodb://localhost:27017/test' , { bufferCommands: true }); mongoose.model( 'Test' , new Schema({}, { bufferCommands: false }));

Moving On