Search⌘ K
AI Features

Middleware (Pre/Post Hooks): Hashing Passwords as an Example

Explore how Mongoose middleware hooks like pre('save') and post('save') enable automatic password hashing during the document lifecycle in MERN applications. Understand why placing password hashing in schema middleware ensures consistent security, prevents storing plain text passwords, and maintains data integrity across different update methods.

Mongoose sits between a Node.js application, often built with Express, and MongoDB, turning plain JavaScript objects into Mongoose documents with schema-based behavior, validation, and hooks that run around model operations. In Mongoose, middleware refers to pre and post functions that run before or after a model operation, so repeated data logic can run automatically during a document lifecycle instead of being duplicated across route handlers.

For a MERN application, that adds a structured processing step to the write path. The request body arrives as JSON, the Express JSON middleware parses it into a JavaScript object; Mongoose turns it into a document instance, and middleware can inspect or transform the document before the write completes. The MongoDB driver then serializes it to BSON for storage. This lesson focuses on document middleware, especially pre('validate'), pre('save'), and post('save'), using password hashing on the users collection as the working example.

A good schema should enforce more than field types. It should also enforce repeated write-time behavior, such as making sure password is never persisted in plain text. That is the role of hooks in this chapter, and the same pattern will reappear later when the authentication flow is built end to end.

Before looking at code, it helps to visualize where each hook runs in the document life cycle.

Mongoose user document life cycle and middleware comparison
Mongoose user document life cycle and middleware comparison

That life cycle framing leads directly to the schema design decision.

Why hooks belong in the schema

If password hashing lives only in controllers, the system depends on every route author remembering to do the same work in the same order. One missed code path can write a plain password to users, and once that state is in MongoDB, later reads and login checks become inconsistent.

Placing the rule in the schema changes the control point. Every call to doc.save() routes through the same middleware chain, so the User model itself becomes the enforcement boundary. This is a maintainability vs. flexibility trade-off. Controller-level hashing gives more local control, but ...