DEV Community

Cover image for Argon2 vs bcrypt vs PBKDF2 in Node.js: Which Password Hashing Algorithm Should You Use in 2026?
Dulaj Thiwanka
Dulaj Thiwanka

Posted on

Argon2 vs bcrypt vs PBKDF2 in Node.js: Which Password Hashing Algorithm Should You Use in 2026?

Introduction

Password storage is one of the most important security decisions when building a backend application.

A common mistake developers make is storing passwords using fast hashing algorithms like:

SHA256(password)
MD5(password)
Enter fullscreen mode Exit fullscreen mode

These algorithms are designed to be fast, which makes them perfect for data integrity checks but terrible for password storage.

If your database is leaked, attackers can use GPUs and password-cracking tools to test billions of passwords.

attackflow
Modern password hashing algorithms solve this problem by intentionally making password cracking expensive.

The three most common choices in Node.js applications are:

  • Argon2id
  • bcrypt
  • PBKDF2

This article explains how each works and how to implement them correctly in Node.js applications.


1. Password Hashing Flow in a Node.js Application

A secure authentication system follows this flow:

User Registration
        |
        |
        v
User enters password
        |
        |
        v
Generate random salt
        |
        |
        v
Password Hashing Algorithm
        |
        |
        v
Store Hash in Database
Enter fullscreen mode Exit fullscreen mode

hashing

Example database:

{
    "email": "user@example.com",
    "password": "$argon2id$v=19$m=65536,t=3,p=4$..."
}
Enter fullscreen mode Exit fullscreen mode

During login:

User Login
     |
     |
     v
Enter Password
     |
     |
     v
Retrieve Stored Hash
     |
     |
     v
Verify Password
     |
     |
     v
Allow / Reject Login
Enter fullscreen mode Exit fullscreen mode

2. Argon2id Implementation in Node.js

What is Argon2id?

Argon2id is currently the recommended password hashing algorithm for new applications.

It was designed to resist:

  • GPU cracking attacks
  • Password dictionary attacks
  • Large-scale offline attacks

Unlike bcrypt and PBKDF2, Argon2id is memory-hard.

That means an attacker cannot simply add more GPUs to increase cracking speed.

argon2

Installing Argon2

Install the package:

npm install argon2
Enter fullscreen mode Exit fullscreen mode

Basic Argon2id Password Hashing

Example:

const argon2 = require("argon2");


async function hashPassword(password){

    const hash = await argon2.hash(password,{
        type: argon2.argon2id
    });

    return hash;
}


async function verifyPassword(password,hash){

    return await argon2.verify(
        hash,
        password
    );
}
Enter fullscreen mode Exit fullscreen mode

Argon2id Configuration

Production systems should configure the cost parameters.

Example:

const hash = await argon2.hash(password,{

    type: argon2.argon2id,

    memoryCost: 65536,

    timeCost: 3,

    parallelism: 4

});
Enter fullscreen mode Exit fullscreen mode

argon2conf

Understanding Argon2 Settings

memoryCost

Controls RAM usage.

Example:

memoryCost: 65536
Enter fullscreen mode Exit fullscreen mode

means:

65536 KB

≈

64 MB RAM
Enter fullscreen mode Exit fullscreen mode

Higher value:

More security
+
More server memory usage
Enter fullscreen mode Exit fullscreen mode

timeCost

Number of iterations.

Example:

timeCost:3
Enter fullscreen mode Exit fullscreen mode

means:

Password processing happens 3 times
Enter fullscreen mode Exit fullscreen mode

parallelism

Number of CPU threads.

Example:

parallelism:4
Enter fullscreen mode Exit fullscreen mode

means:

Use 4 parallel lanes
Enter fullscreen mode Exit fullscreen mode

Recommended Node.js Production Config

const ARGON_CONFIG = {

    type: argon2.argon2id,

    memoryCost: 65536,

    timeCost: 3,

    parallelism: 4

};
Enter fullscreen mode Exit fullscreen mode

Complete User Registration Example

const argon2 = require("argon2");


async function registerUser(password){

    const passwordHash =
        await argon2.hash(
            password,
            ARGON_CONFIG
        );


    await User.create({

        password: passwordHash

    });

}
Enter fullscreen mode Exit fullscreen mode

Database stores:

$argon2id$v=19$m=65536,t=3,p=4$...
Enter fullscreen mode Exit fullscreen mode

The configuration is stored inside the hash.

You do not need to save:

memoryCost
timeCost
parallelism
Enter fullscreen mode Exit fullscreen mode

separately.


Login Verification

async function login(password,storedHash){

    const valid =
        await argon2.verify(
            storedHash,
            password
        );


    if(valid){

        return "Login success";

    }


    throw Error("Invalid password");

}
Enter fullscreen mode Exit fullscreen mode

3. bcrypt Implementation in Node.js

What is bcrypt?

bcrypt is one of the oldest and most widely used password hashing algorithms.

It is still secure when configured correctly.

Many existing Node.js applications use bcrypt.


Installing bcrypt

npm install bcrypt
Enter fullscreen mode Exit fullscreen mode

Basic bcrypt Example

const bcrypt = require("bcrypt");


async function hashPassword(password){

    const saltRounds = 12;


    return await bcrypt.hash(
        password,
        saltRounds
    );

}
Enter fullscreen mode Exit fullscreen mode

Understanding bcrypt Cost Factor

Example:

bcrypt.hash(password,12)
Enter fullscreen mode Exit fullscreen mode

The number:

12
Enter fullscreen mode Exit fullscreen mode

is the cost factor.

Calculation:

2^cost
Enter fullscreen mode Exit fullscreen mode

Example:

cost 10

=
1024 rounds


cost 12

=
4096 rounds
Enter fullscreen mode Exit fullscreen mode

Higher cost:

More secure
+
Slower login
Enter fullscreen mode Exit fullscreen mode

costfactor

Recommended bcrypt Configuration

const BCRYPT_ROUNDS = 12;
Enter fullscreen mode Exit fullscreen mode

For high-security applications:

const BCRYPT_ROUNDS = 14;
Enter fullscreen mode Exit fullscreen mode

bcrypt Verification

const match =
await bcrypt.compare(
    userPassword,
    databaseHash
);


if(match){

    console.log("Authenticated");

}
Enter fullscreen mode Exit fullscreen mode

bcrypt Limitations

bcrypt has one major limitation:

Maximum password length:

72 bytes
Enter fullscreen mode Exit fullscreen mode

Example:

VeryLongPassword....................

Only first 72 bytes processed
Enter fullscreen mode Exit fullscreen mode

For new systems, Argon2id is usually preferred.


4. PBKDF2 Implementation in Node.js

What is PBKDF2?

PBKDF2 is a password-based key derivation algorithm.

It is commonly used in:

  • Enterprise systems
  • Banking systems
  • Compliance environments

Node.js already includes PBKDF2 through the built-in crypto module.

No package installation required.


PBKDF2

PBKDF2 Example

const crypto = require("crypto");


function hashPassword(password){

    const salt =
    crypto.randomBytes(16)
    .toString("hex");


    const hash =
    crypto.pbkdf2Sync(

        password,

        salt,

        600000,

        64,

        "sha256"

    );


    return {

        salt,

        hash:
        hash.toString("hex")

    };

}
Enter fullscreen mode Exit fullscreen mode

PBKDF2 Configuration

crypto.pbkdf2Sync(

password,

salt,

iterations,

keyLength,

digest

)
Enter fullscreen mode Exit fullscreen mode

Example:

600000
Enter fullscreen mode Exit fullscreen mode

means:

600,000 iterations
Enter fullscreen mode Exit fullscreen mode

Recommended PBKDF2 Settings

{

iterations:600000,

keyLength:64,

algorithm:"sha256"

}
Enter fullscreen mode Exit fullscreen mode

PBKDF2 Verification

function verifyPassword(
password,
salt,
storedHash
){

const hash =
crypto.pbkdf2Sync(

password,

salt,

600000,

64,

"sha256"

);


return (
hash.toString("hex")
===
storedHash
);

}
Enter fullscreen mode Exit fullscreen mode

5. Node.js Configuration Comparison

Algorithm Package Configuration
Argon2id argon2 memory, iterations, parallelism
bcrypt bcrypt salt rounds
PBKDF2 crypto iterations, key length

compare

6. Environment-Based Configuration

Do not hardcode security settings.

Example:

.env

PASSWORD_ALGORITHM=argon2id

ARGON_MEMORY=65536
ARGON_TIME=3
ARGON_PARALLELISM=4

BCRYPT_ROUNDS=12

PBKDF2_ITERATIONS=600000
Enter fullscreen mode Exit fullscreen mode

Configuration file:

module.exports={

argon2:{
memoryCost:
Number(process.env.ARGON_MEMORY),

timeCost:
Number(process.env.ARGON_TIME),

parallelism:
Number(process.env.ARGON_PARALLELISM)

},


bcrypt:{
rounds:
Number(process.env.BCRYPT_ROUNDS)
}

};
Enter fullscreen mode Exit fullscreen mode

7. Migrating bcrypt Users to Argon2id

You don't need to reset every password.

Migration flow:

User Login

      |

Check bcrypt hash

      |

Password correct?

      |

Generate Argon2id hash

      |

Replace old hash

Enter fullscreen mode Exit fullscreen mode

Example:

if(await bcrypt.compare(password,user.password)){


const newHash =
await argon2.hash(
password,
ARGON_CONFIG
);


user.password=newHash;

await user.save();

}
Enter fullscreen mode Exit fullscreen mode

Migration happens automatically.

migration

8. Final Recommendation for Node.js Developers in 2026

New Projects

Use:

Argon2id
Enter fullscreen mode Exit fullscreen mode

Example stack:

Node.js
+
Express
+
PostgreSQL/MongoDB
+
Argon2id
+
JWT/Session
+
MFA
Enter fullscreen mode Exit fullscreen mode

Existing Applications

If you already use bcrypt:

Keep bcrypt

+

Increase cost factor

+

Gradually migrate to Argon2id
Enter fullscreen mode Exit fullscreen mode

Enterprise Applications

If compliance requires it:

PBKDF2-HMAC-SHA256
Enter fullscreen mode Exit fullscreen mode

Final Security Checklist

A production authentication system should have:

✅ Argon2id/bcrypt/PBKDF2
✅ Unique salt per password
✅ Rate limiting
✅ Account lockout protection
✅ MFA support
✅ Password breach detection
✅ Secure session management
✅ HTTPS everywhere


final

Conclusion

For Node.js applications in 2026:

Argon2id is the default choice for new systems.

bcrypt remains reliable for existing applications, while PBKDF2 continues to be useful where compliance standards require it.

The best implementation is not only choosing a strong hashing algorithm but also correctly configuring it, monitoring performance, and combining it with other authentication security layers.

Top comments (0)