Why you should use bcrypt over MD5 and SHA for password storage, how the cost factor works, and implementation examples in Node.js.
When users create accounts, you must store something that lets you verify their password later — but not the password itself. If your database leaks, plaintext passwords would instantly compromise every account.
The solution: store a cryptographic hash of the password. But not all hashes are equal.
MD5 and SHA (SHA-1, SHA-256, etc.) are general-purpose hash functions designed for speed — they can hash billions of values per second on modern GPUs.
For file integrity checks, that speed is great. For passwords, it's catastrophic:
MD5 GPU throughput: ~200 billion hashes/second
SHA-256 GPU throughput: ~10 billion hashes/second
bcrypt (cost=10): ~40 hashes/second
An attacker with a dictionary of 1 billion common passwords can crack MD5-hashed passwords in under 5 seconds. With bcrypt at cost=10, that same attack takes 29 million seconds (~338 days).
Bcrypt was designed in 1999 by Niels Provos and David Mazières specifically for password hashing. It has three key properties:
1. Adaptive cost factor. The rounds parameter (also called the work factor or cost factor) controls how slow the hash is to compute. With each increment, the computation time doubles:
| Cost | Approximate time (modern CPU) |
|---|---|
| 10 | ~100ms |
| 11 | ~200ms |
| 12 | ~400ms |
| 13 | ~800ms |
| 14 | ~1.6s |
As hardware gets faster, you increase the cost factor to keep the computation slow.
2. Built-in salt. Bcrypt generates a random 22-character salt automatically and embeds it in the hash output. This prevents rainbow table attacks and ensures that the same password produces a different hash each time.
3. Maximum length. Bcrypt truncates input at 72 bytes. For most use cases this is fine, but be aware of it for very long passwords.
A bcrypt hash looks like this:
$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
Breaking it down:
$2a$ — algorithm version (2a, 2b, 2y are all bcrypt)
10$ — cost factor
N9qo8uLOickgx2ZMRZoMye — 22-char salt (base64 encoded)
IjZAgcfl7p92ldGxad68LJZdL17lhWy — 31-char hash
npm install bcryptjs
import bcrypt from 'bcryptjs';
// Hashing a password
async function hashPassword(password) {
const saltRounds = 12; // Good for 2025
return bcrypt.hash(password, saltRounds);
}
// Verifying a password
async function checkPassword(password, hash) {
return bcrypt.compare(password, hash);
}
// Usage
const hash = await hashPassword('user-password-123');
// Store 'hash' in your database
// On login:
const isValid = await checkPassword('user-password-123', hash);
if (!isValid) throw new Error('Invalid credentials');
The OWASP recommendation for 2025 is cost factor 10 at minimum, with 12 as a better default if your server can handle the load. A simple rule: choose the highest cost factor that keeps login response time under 300ms on your production hardware.
// Test cost factor performance
async function benchmarkBcrypt(rounds) {
const start = Date.now();
await bcrypt.hash('test-password', rounds);
return Date.now() - start;
}
// Run and adjust based on your server
for (const r of [10, 11, 12, 13]) {
const ms = await benchmarkBcrypt(r);
console.log(`rounds=${r}: ${ms}ms`);
}
Don't hash before hashing. Never MD5 or SHA the password before bcrypt — bcrypt's 72-byte limit combined with base64 output from MD5 can cause collisions.
Don't use sync variants in production. bcrypt.hashSync blocks the Node.js event loop. Always use the async Promise-based API.
Do compare the full hash. Never implement your own substring comparison. Always use bcrypt.compare which uses constant-time comparison to prevent timing attacks.
Use HeoLab's Bcrypt Generator to hash passwords and verify them against existing hashes directly in your browser — no backend required, 100% client-side.
Bcrypt is the battle-tested standard for password hashing. It's slow by design, includes salt automatically, and adapts to faster hardware over time. In 2025, use bcrypt (or Argon2id if you want the newest standard) and use nothing else for storing user passwords.
Bcrypt Generator
Hash passwords with bcrypt and verify bcrypt hashes. Choose work factor 4–14.
Hash Generator
Generate MD5, SHA-1, SHA-256, and SHA-512 hashes from any text. Compare all algorithms side by side.
Password Generator
Generate cryptographically secure passwords with custom length, character sets, and strength analysis.