Fork me on GitHub


Middleware are functions which are passed control of flow during execution of init, validate, save and remove methods. There are two types of middleware, pre and post. Let's start with pre.


There are two types of pre middleware, serial and parallel.


Serial middleware are executed one after another, when each middleware calls next.

var schema = new Schema(..);
schema.pre('save', function (next) {
  // do stuff


Parallel middleware offer more fine-grained flow control.

var schema = new Schema(..);
schema.pre('save', true, function (next, done) {
  // calling next kicks off the next middleware in parallel

The hooked method, in this case save, will not be executed until done is called by each middleware.

Use Cases

Middleware are useful for atomizing model logic and avoiding nested blocks of async code. Here are some other ideas:

Error handling

If any middleware calls next or done with an Error instance, the flow is interrupted, and the error is passed to the callback.

schema.pre('save', function (next) {
  var err = new Error('something went wrong');

// later... (err) {
  console.log(err.message) // something went wrong

Post middleware

post middleware are executed after the hooked method and all of its pre middleware have completed. post middleware do not directly receive flow control, e.g. no next or done callbacks are passed to it. post hooks are a way to register traditional event listeners for these methods.'init', function (doc) {
  console.log('%s has been initialized from the db', doc._id);
})'validate', function (doc) {
  console.log('%s has been validated (but not saved yet)', doc._id);
})'save', function (doc) {
  console.log('%s has been saved', doc._id);
})'remove', function (doc) {
  console.log('%s has been removed', doc._id);

Next Up

Now that we've covered middleware, let's take a look at Mongooses approach to faking JOINs with its query population helper.