Hashing strings in Node.js is a fundamental skill for building secure applications. Whether you need to hash strings in Node.js for checksums, cache keys, file integrity, or password storage, choosing the right algorithm matters enormously. This guide covers the built-in crypto module for general-purpose hashing (SHA-256, MD5, SHA-512) and bcryptjs for password hashing — and explains clearly when each approach is appropriate.
The Node.js crypto Module (Built-in, No Dependencies)
Node.js ships with a built-in crypto module that covers nearly every general-purpose hashing need. No npm install required.
SHA-256 Hashing
const crypto = require('crypto');
function sha256(input) {
return crypto.createHash('sha256').update(input).digest('hex');
}
console.log(sha256('Hello, World!'));
// "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986d"
// Hash a Buffer (for binary data)
const fileBuffer = require('fs').readFileSync('package.json');
const checksum = crypto.createHash('sha256').update(fileBuffer).digest('hex');
console.log('File SHA-256:', checksum);
SHA-512 Hashing
function sha512(input) {
return crypto.createHash('sha512').update(input, 'utf8').digest('hex');
}
// Base64-encoded output (shorter string)
function sha512Base64(input) {
return crypto.createHash('sha512').update(input, 'utf8').digest('base64');
}
MD5 Hashing
function md5(input) {
return crypto.createHash('md5').update(input).digest('hex');
}
console.log(md5('hello'));
// "5d41402abc4b2a76b9719d911017c592"
Important: MD5 is cryptographically broken. Never use it for security-sensitive purposes. It is still useful for non-security use cases like cache keys, deduplication hashes, and ETag generation where collision resistance is not required.
HMAC (Keyed Hash for APIs)
When you need to verify that a message has not been tampered with — such as webhook signature verification — use HMAC rather than a plain hash:
const crypto = require('crypto');
function createHMAC(message, secret) {
return crypto
.createHmac('sha256', secret)
.update(message)
.digest('hex');
}
// Verify a webhook signature (e.g., Stripe, GitHub)
function verifyWebhookSignature(payload, receivedSig, secret) {
const expectedSig = createHMAC(payload, secret);
// Use timingSafeEqual to prevent timing attacks
return crypto.timingSafeEqual(
Buffer.from(expectedSig, 'hex'),
Buffer.from(receivedSig, 'hex')
);
}
const sig = createHMAC('{"event":"payment"}', 'my-webhook-secret');
console.log('HMAC-SHA256:', sig);
Password Hashing with bcryptjs
SHA-256 and SHA-512 are fast hash functions — that is exactly what makes them wrong for password storage. An attacker with a GPU can try billions of SHA-256 guesses per second. Password hashing requires a deliberately slow algorithm with a configurable cost factor: bcrypt, Argon2, or scrypt.
npm install bcryptjs
const bcrypt = require('bcryptjs');
// Hash a password (async — preferred)
async function hashPassword(plaintext) {
const saltRounds = 12; // Higher = slower = more secure
return bcrypt.hash(plaintext, saltRounds);
}
// Verify a password against a stored hash
async function verifyPassword(plaintext, storedHash) {
return bcrypt.compare(plaintext, storedHash);
}
// Usage
async function example() {
const hash = await hashPassword('my-secure-password');
console.log('Hash:', hash);
// "$2a$12$..."
const isValid = await verifyPassword('my-secure-password', hash);
console.log('Valid:', isValid); // true
const isWrong = await verifyPassword('wrong-password', hash);
console.log('Wrong:', isWrong); // false
}
Choosing the Salt Rounds
The saltRounds (cost factor) controls how slow hashing is. A higher number doubles the work for each increment:
- 10 — ~100ms per hash, minimum acceptable for production
- 12 — ~400ms per hash, recommended default in 2026
- 14 — ~1.5s per hash, for high-security applications
Pick a value where hashing takes about 250–500ms on your production hardware. Re-evaluate every year or two as hardware improves.
scrypt (Built-in Node.js Alternative to bcrypt)
Node.js 10+ includes crypto.scrypt(), which is another memory-hard password hashing function without any npm dependency:
const crypto = require('crypto');
const { promisify } = require('util');
const scrypt = promisify(crypto.scrypt);
async function hashPasswordScrypt(password) {
const salt = crypto.randomBytes(32).toString('hex');
const derivedKey = await scrypt(password, salt, 64);
return `${salt}:${derivedKey.toString('hex')}`;
}
async function verifyPasswordScrypt(password, stored) {
const [salt, keyHex] = stored.split(':');
const derivedKey = await scrypt(password, salt, 64);
return crypto.timingSafeEqual(
Buffer.from(keyHex, 'hex'),
derivedKey
);
}
Hashing Files for Integrity Checks
const crypto = require('crypto');
const fs = require('fs');
function hashFile(filePath, algorithm = 'sha256') {
return new Promise((resolve, reject) => {
const hash = crypto.createHash(algorithm);
const stream = fs.createReadStream(filePath);
stream.on('data', chunk => hash.update(chunk));
stream.on('end', () => resolve(hash.digest('hex')));
stream.on('error', reject);
});
}
// Usage
hashFile('./dist/bundle.js').then(checksum => {
console.log('SHA-256:', checksum);
});
Algorithm Selection Guide
- SHA-256 — checksums, file integrity, API request signing, cache keys (non-password)
- SHA-512 — higher security margin, slightly slower, good for token generation
- MD5 — legacy compatibility, ETags, non-security deduplication only
- HMAC-SHA256 — webhook verification, API authentication, message authentication codes
- bcrypt / scrypt / Argon2 — password storage, always and only
For quick hash generation during development and testing, the hash generator tool computes MD5, SHA-1, SHA-256, and SHA-512 hashes instantly in the browser.
Summary
- Use Node.js built-in
crypto.createHash()for all non-password hashing — no dependencies needed - SHA-256 is the safe default for general-purpose cryptographic hashing
- MD5 is acceptable for checksums and cache keys, never for security
- Always use bcrypt, scrypt, or Argon2 for password hashing — never SHA-* for passwords
- Use
crypto.timingSafeEqual()for constant-time signature comparison - Store the salt alongside the hash — bcrypt encodes it in the output automatically
Want these tools available offline? The DevToolkit Bundle ($9 on Gumroad) packages 40+ developer tools into a single downloadable kit — no internet required.
Free Developer Tools
If you found this article helpful, check out DevToolkit — 40+ free browser-based developer tools with no signup required.
Popular tools: JSON Formatter · Regex Tester · JWT Decoder · Base64 Encoder
🛒 Get the DevToolkit Starter Kit on Gumroad — source code, deployment guide, and customization templates.
Top comments (0)