DevTools Hub

Search tools

Search for a developer tool

Hashing

Bcrypt Cost Calculator

Benchmark bcrypt cost factors live and find one that hits your target time.

Part of the Hashing Toolkit

Runs real bcrypt hashes at increasing cost factors, timed in this tab.

This measures WASM bcrypt in this browser, on this device — not your production server. A server's native bcrypt binding can be meaningfully faster or slower than this, depending on hardware and implementation. Use this to understand the cost-factor-to-time relationship, then confirm the real number on your actual server with the snippets below.
Node.js (bcrypt package)
const bcrypt = require("bcrypt");

for (let cost = 10; cost <= 14; cost++) {
  const start = process.hrtime.bigint();
  await bcrypt.hash("benchmark-password-value", cost);
  const ms = Number(process.hrtime.bigint() - start) / 1e6;
  console.log(`cost=${cost}: ${ms.toFixed(1)}ms`);
}
Python (bcrypt package)
import bcrypt, time

for cost in range(10, 15):
    start = time.perf_counter()
    bcrypt.hashpw(b"benchmark-password-value", bcrypt.gensalt(cost))
    ms = (time.perf_counter() - start) * 1000
    print(f"cost={cost}: {ms:.1f}ms")

What this does

bcrypt's cost factor controls how slow it is on purpose — each +1 roughly doubles the work, since the cost factor is a base-2 exponent for the number of rounds. This tool runs real bcrypt hashes at increasing cost factors, timed live in your browser, so you can see that doubling relationship with real numbers instead of taking it on faith, then extrapolates a cost factor for whatever target time you enter.

Why the recommendation isn't the final answer

This benchmark measures WebAssembly bcrypt running in your browser's JavaScript engine, on whatever device you're reading this on — not your production server's native bcrypt binding (a compiled C extension in Node, Python, Go, or similar), which can be meaningfully faster or slower depending on hardware and implementation. Treat the recommended cost factor here as a starting point for understanding the relationship, not as the number to paste directly into production. The two code snippets below run the same kind of benchmark server-side, in Node.js and Python, using the actual libraries a real deployment would use — that's the number that actually matters.

How the extrapolation works

Rather than benchmarking every cost factor up to a high one (which would freeze the tab for longer than necessary), this anchors on the highest cost factor it actually measured — the most reliable reading, since very low cost factors finish fast enough that fixed WASM call overhead and timer resolution dominate the result rather than real work — and extrapolates using bcrypt's doubling relationship: time(cost) ≈ time(anchor) × 2^(cost − anchor). The benchmark stops automatically once a single cost factor takes about a second, both to keep the browser responsive and because that's already a reliable anchor point.

Picking a target time

There's no single official number — OWASP's guidance is a cost factor of at least 10, and otherwise "as large as verification server performance will allow." In practice, many teams target somewhere in the 100–500ms range for a single login hash: fast enough that a real user doesn't notice it, slow enough to meaningfully throttle an attacker running billions of parallel guesses against a stolen hash. Your own budget depends on your login endpoint's traffic and acceptable latency.

FAQ

Is anything sent anywhere?

No — the benchmark and every hash computed here run entirely in your browser.

I just want to generate a bcrypt hash at a specific cost factor

See Password Hash Generator, which also covers scrypt, Argon2, and PBKDF2.

I have an existing hash and want to know its cost factor

Password Hash Inspector decodes an existing bcrypt hash's version, cost factor, salt, and hash — and flags a cost factor below OWASP's minimum automatically.

Why does the benchmark start over at a low cost factor instead of resuming?

Each run uses a fresh random salt and includes a throwaway warm-up call, so early WASM/JIT startup costs don't skew the first real reading. Re-running gives a second, independent measurement if the first looked noisy.

Related tools