· 3 min read · 758 words
Which Bcrypt Cost Factor Should You Use in 2026?
Cost 12 is the answer for most web applications. Here is how to check that against your own hardware, and what actually goes wrong at the low and high ends.
- bcrypt
- cost factor
- performance
The short answer is 12. If you want the reasoning, or you are running on hardware that makes 12 a bad fit, the rest of this is worth reading.
What the number actually controls
The cost factor is an exponent, not a multiplier. Cost 12 means bcrypt runs 2 to the power of 12 iterations, so 4,096 of them. Cost 13 runs 8,192. Every step up doubles the time the hash takes, for you and for anyone trying to guess passwords against your database.
This is the entire point of bcrypt. A fast hash like SHA-256 is a liability for passwords precisely because it is fast, and a graphics card can try billions of SHA-256 guesses per second. Bcrypt lets you dial the speed down until guessing stops being worth the electricity.
Pick a target time, not a number
The useful way to choose is to decide how long a login is allowed to take, then find the cost that lands there on your production hardware. Somewhere between 250 and 500 milliseconds is the range most teams settle on. Users do not notice it, and it puts a hard ceiling on how fast an attacker can work through a stolen table.
The tool on the homepage reports how long each hash took in your browser. That is a rough proxy, because your laptop is not your server, but it gets you into the right neighbourhood quickly.
Measure on the machine that will run it. A shared container with a fraction of a CPU behaves nothing like a dedicated server, and the difference is often two whole cost steps.
What goes wrong below 10
Cost 10 was a reasonable default in 2015 and is the value several libraries still ship. On current hardware a cost 10 hash finishes in well under 100 milliseconds, which means a rented GPU box can work through a large fraction of a common password list in a weekend.
Anything at or below 8 is not worth the trouble of running bcrypt at all. You have paid the complexity cost of a slow hash and kept almost none of the benefit.
What goes wrong above 14
The failure mode at the top end is not security, it is availability. Every login now costs you real CPU time, and login is the one endpoint that gets hammered during an incident. At cost 15 on a modest server you are looking at a second or more per attempt, and a few hundred concurrent logins will queue up behind each other until the whole thing falls over.
That turns your own password hashing into the denial of service. Rate limiting helps, but it does not change the arithmetic of how much CPU a legitimate login burns.
A rough table
| Cost | Iterations | Roughly | Verdict |
|---|---|---|---|
| 8 | 256 | under 10 ms | Too cheap to bother |
| 10 | 1,024 | about 50 ms | Old default, raise it |
| 12 | 4,096 | about 200 ms | Sensible for most sites |
| 13 | 8,192 | about 400 ms | Good if you can afford it |
| 14 | 16,384 | about 800 ms | Only with capacity to spare |
| 15+ | 32,768+ | over 1.5 s | Your logins are the bottleneck |
Those times come from a recent laptop CPU. Treat them as shape, not as measurement, and run your own numbers.
Raising the cost on an existing database
You do not need a migration or a password reset. The cost is stored inside the hash string, so old and new hashes coexist without any special handling. Verification reads the cost out of the stored hash and uses it.
Rehash on successful login. The user has just handed you the plaintext, so you can check the cost of the stored hash and, if it is below your current target, write a fresh one before you finish the request.
const ok = await bcrypt.compare(password, user.passwordHash);
if (!ok) return fail();
// The cost sits between the second and third dollar sign.
const storedCost = Number(user.passwordHash.split('$')[2]);
if (storedCost < 12) {
user.passwordHash = await bcrypt.hash(password, 12);
await user.save();
}Within a few months most active accounts have moved over on their own. Whatever is left belongs to people who have not logged in, and you can leave those alone until they do.
One thing the cost factor will not fix
Bcrypt reads at most 72 bytes of the password and silently ignores the rest. No cost factor changes that, and it catches people out when they hash a long passphrase or a base64 encoded value. There is a separate write up on the 72 byte limit if that is relevant to you.