New to Rust? Grab our free Rust for Beginners eBook Get it free →
Password Hashing in Node.js with Bcrypt

Password hashing in Node.js with bcrypt means storing a slow, salted hash instead of the password itself. The async bcrypt API creates the hash during registration or a password change, then compares a login attempt against the stored hash.
The example below uses the current bcrypt package and prints the checks that matter: the saved cost, a valid password result, and a rejected changed password. Bcrypt is established for systems that already use bcrypt, while OWASP lists Argon2id as its preferred choice for a new password-storage design.
Install bcrypt
Install bcrypt inside the Node.js project that owns registration and login. The package supplies Promise-based async methods when you omit a callback.
npm install bcrypt
Hash and verify a password
Pass the plaintext password and a bcrypt cost to hash, store only the returned hash, then pass the submitted password and stored hash to compare during login.
const bcrypt = require('bcrypt');
async function verifyPassword() {
const password = 'CorrectHorseBatteryStaple!';
const storedHash = await bcrypt.hash(password, 12);
console.log(`Hash prefix: ${storedHash.slice(0, 7)}`);
console.log(`Stored cost: ${bcrypt.getRounds(storedHash)}`);
console.log(`Password accepted: ${await bcrypt.compare(password, storedHash)}`);
console.log(`Changed password accepted: ${await bcrypt.compare('wrong password', storedHash)}`);
}
verifyPassword().catch((error) => {
console.error(error);
process.exitCode = 1;
});
A successful run reports cost 12, accepts the original password, and rejects the changed value because bcrypt generates a new salt for each hash, which makes matching hash strings unsuitable for password validation.

What bcrypt stores in the hash
A bcrypt hash carries the algorithm identifier, cost, salt, and derived value in one string, which lets compare validate the plaintext submission against the saved hash without a second manually generated hash.
The bcrypt README notes that only the first 72 bytes of a string participate in bcrypt processing. A password with emoji or other multibyte characters can reach that limit before it reaches 72 characters, so define and test your application’s input-length rule.
Choose a cost and handle limits
The cost controls the amount of work bcrypt performs. A higher cost slows password guesses and also slows your own registration and login requests, so measure the async hash call on the hardware that will serve your application.
OWASP documents a bcrypt work factor of at least 10 for legacy systems that use bcrypt. Cost 12 is a useful starting point for this example, not a universal deployment value.
Put bcrypt at the authentication boundary
Call hash when you create or change a password, and call compare when you authenticate a login. Keep the stored hash in your user record and keep it out of logs, API responses, and browser storage.
If you are building a token-based login flow, pair this step with the JWT authentication API walkthrough, where token issuance and verification govern the authenticated session after the password hash protects the stored credential.
Password hashing does not replace rate limiting, secure password resets, transport protection, session controls, or multi-factor authentication. Apply the adjacent controls in the Node.js security practices guide around the login route.
FAQ
The bcrypt package handles the salt inside hash when you pass a numeric cost. These answers cover the implementation choices that affect a login flow.
Should I hash the submitted password before calling bcrypt.compare?
No. Pass the plaintext password submitted at login and the stored bcrypt hash to bcrypt.compare. The function reads the salt and cost from the stored hash.
Why does bcrypt create a different hash for the same password?
bcrypt generates a salt for each hash. The stored hash contains that salt, so bcrypt.compare can validate the password without requiring matching hash strings.
Is bcrypt suitable for a new Node.js application?
OWASP lists Argon2id as its preferred password hashing algorithm for new systems. bcrypt remains useful when an existing application already stores bcrypt hashes, provided you choose and measure an appropriate work factor.
Keep the hash call in registration or password-change code, then call compare only at login, so the stored hash stays the record of the chosen cost and salt.
Sources
bcrypt on npm and the bcrypt README document the Node.js API and input boundary. OWASP Password Storage Cheat Sheet documents password-storage recommendations.



