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.

Implementation

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.

Try It — Bcrypt Generator

Open full tool