Using Bcrypt in Node.js
Complete guide to using bcrypt in Node.js applications. Covers the bcrypt and bcryptjs libraries, async vs sync APIs, Express.js integration, and best practices for production deployments.
Detailed Explanation
Using Bcrypt in Node.js
Node.js has two primary bcrypt libraries: bcrypt (native C++ bindings) and bcryptjs (pure JavaScript). Both provide the same API, but differ in performance and installation requirements.
Library Comparison
| Feature | bcrypt | bcryptjs |
|---|---|---|
| Implementation | Native C++ addon | Pure JavaScript |
| Speed | ~3x faster | Slower but adequate |
| Installation | Requires build tools (node-gyp) | No native dependencies |
| Platform support | May fail on some ARM/Alpine builds | Works everywhere |
For production, bcrypt is preferred for performance. For serverless or Docker environments where native compilation is problematic, bcryptjs is a reliable alternative.
Installation
# Native (faster)
npm install bcrypt
# Pure JS (no build tools needed)
npm install bcryptjs
Hashing a Password
const bcrypt = require('bcrypt');
const SALT_ROUNDS = 12;
// Async (recommended)
async function hashPassword(plaintext) {
return await bcrypt.hash(plaintext, SALT_ROUNDS);
}
// Sync (use only in scripts, never in request handlers)
function hashPasswordSync(plaintext) {
return bcrypt.hashSync(plaintext, SALT_ROUNDS);
}
Verifying a Password
async function verifyPassword(plaintext, storedHash) {
return await bcrypt.compare(plaintext, storedHash);
}
// Usage in Express.js
app.post('/login', async (req, res) => {
const user = await db.findUser(req.body.email);
if (!user) return res.status(401).json({ error: 'Invalid credentials' });
const valid = await bcrypt.compare(req.body.password, user.passwordHash);
if (!valid) return res.status(401).json({ error: 'Invalid credentials' });
const token = generateJWT(user);
res.json({ token });
});
Async vs Sync
Always use async methods in server contexts. Bcrypt hashing is CPU-intensive. Using hashSync or compareSync in an Express route handler blocks the Node.js event loop, preventing all other requests from being processed during hashing.
The async methods run the computation in a worker thread (for native bcrypt) or yield to the event loop periodically (for bcryptjs).
Cost Factor Configuration
// Store as environment variable for easy adjustment
const SALT_ROUNDS = parseInt(process.env.BCRYPT_ROUNDS || '12', 10);
Error Handling
try {
const hash = await bcrypt.hash(password, SALT_ROUNDS);
} catch (err) {
// Handle errors: invalid salt rounds, encoding issues
console.error('Hashing failed:', err.message);
}
Bcrypt will throw if the password is not a string or buffer, or if the salt rounds value is invalid.
Use Case
Node.js is one of the most popular platforms for building web APIs, and bcrypt integration is a fundamental requirement for any application with user accounts. This guide helps Node.js developers choose the right library, avoid the sync-vs-async pitfall that can cripple server performance, and structure their authentication code following production best practices.