Built-in Promises

Mongoose async operations, like .save() and queries, return thenables. This means that you can do things like MyModel.findOne({}).then() and await MyModel.findOne({}).exec() if you're using async/await.

You can find the return type of specific operations in the api docs You can also read more about promises in Mongoose.

const gnr = new Band({
  name: "Guns N' Roses",
  members: ['Axl', 'Slash']

const promise =;
assert.ok(promise instanceof Promise);

promise.then(function (doc) {
  assert.equal(, "Guns N' Roses");

Queries are not promises

Mongoose queries are not promises. They have a .then() function for co and async/await as a convenience. If you need a fully-fledged promise, use the .exec() function.

const query = Band.findOne({name: "Guns N' Roses"});
assert.ok(!(query instanceof Promise));

// A query is not a fully-fledged promise, but it does have a `.then()`.
query.then(function (doc) {
  // use doc

// `.exec()` gives you a fully-fledged promise
const promise = query.exec();
assert.ok(promise instanceof Promise);

promise.then(function (doc) {
  // use doc

Queries are thenable

Although queries are not promises, queries are thenables. That means they have a .then() function, so you can use queries as promises with either promise chaining or async await

Band.findOne({name: "Guns N' Roses"}).then(function(doc) {
  // use doc

Should You Use exec() With await?

There are two alternatives for using await with queries:

  • await Band.findOne();
  • await Band.findOne().exec();

As far as functionality is concerned, these two are equivalent. However, we recommend using .exec() because that gives you better stack traces.

[require:Should You Use `exec()` With `await`]

Plugging in your own Promises Library

If you're an advanced user, you may want to plug in your own promise library like bluebird. Just set mongoose.Promise to your favorite ES6-style promise constructor and mongoose will use it.

const query = Band.findOne({name: "Guns N' Roses"});

// Use bluebird
mongoose.Promise = require('bluebird');
const bluebirdPromise = query.exec();
assert.equal(bluebirdPromise.constructor, require('bluebird'));

// Use q. Note that you **must** use `require('q').Promise`.
mongoose.Promise = require('q').Promise;
const qPromise = query.exec();
assert.ok(qPromise instanceof require('q').makePromise);
Want to learn how to check whether your favorite npm modules work with async/await without cobbling together contradictory answers from Google and Stack Overflow? Chapter 4 of Mastering Async/Await explains the basic principles for determining whether frameworks like React and Mongoose support async/await. Get your copy!