bcrypt Cost Factor Calculator | Pick a cost factor from your own CPU, not a generic table
OWASP's "use cost 12" advice and the famous bcrypt-speed comparison tables are great starting points, but they were written for someone else's hardware. The right cost factor depends on what your production CPU, container, and traffic profile actually do under load. This page runs bcryptjs in your browser, factor by factor, until it finds the highest one that still fits the login latency budget you set.
💡 About this tool
Every time you bump the bcrypt cost factor by one, the amount of work doubles. If cost 10 takes 50 ms on a machine, cost 12 takes about 200 ms and cost 14 about 800 ms. That exponential growth is what gives bcrypt its brute-force resistance, but it also means that picking the wrong factor by one or two steps either slows your login flow to a crawl or weakens your password storage more than necessary.
The benchmark walks from cost 4 up to your chosen ceiling, hashes a dummy password at each cost with bcryptjs, and shows the measured time per row. The highest cost that still fits under your target time is flagged, and the matching $2b$NN$ prefix appears below — that is the exact prefix your stored hashes will carry, so you can paste it into a unit test or a config readme. If any single cost takes longer than 8 seconds, the run cuts off automatically so a slow ARM laptop will not freeze for half a minute.
The string you type in the "sample password" field is fed only to bcrypt.hash() in your own browser. It is not transmitted anywhere, but you still should not paste a real production password into a test input — use the placeholder string or any throwaway value.
🧐 Frequently Asked Questions
Q. So what cost factor should I actually use in 2026? A. The OWASP Password Storage Cheat Sheet currently lists bcrypt with a work factor of 10 as the floor and 12 as the recommended baseline, with the explicit caveat that you should measure on your own hardware. If your authentication endpoint cannot afford more than 250 ms of CPU per login, run this tool and use whatever number it suggests for your stack.
Q. My MacBook benchmarks bcrypt cost 13 in 180 ms but my Linux VPS struggles at cost 11 — which one wins? A. Production wins. Apple Silicon has unusually fast bcrypt throughput thanks to its branch-prediction and memory hierarchy, so a Mac-based number will almost always be optimistic compared to a t3.small EC2 instance or a $5 DigitalOcean droplet. Open this page from the production-equivalent box (SSH-forward a port, or use Cloud Run / Fly.io with a browser shell) and trust that result.
Q. The first row of the table is suspiciously fast or slow. Bug?
A. Probably not. The first bcrypt.hash() call pays for V8 JIT warm-up and esm.sh module loading. Run the benchmark twice and trust the second pass for borderline decisions. Anything within ±10 % across runs is normal noise; bcryptjs is single-threaded JavaScript, not constant-time native code.
Q. We raised the cost factor and existing users complain logins are slower. How do we step it up gradually?
A. The cost is baked into each stored hash ($2b$10$... vs $2b$12$...), so old hashes keep working at their old cost. Add a rehash-on-login path: when a user authenticates successfully, check bcrypt.getRounds(), and if it is below the new target, hash the supplied plaintext with the new cost and overwrite the row. That spreads the CPU cost across days of normal traffic instead of slamming everyone at once.
Q. Why not just switch to Argon2id?
A. For greenfield systems, Argon2id is the better answer — it is memory-hard, side-channel resistant, and the current OWASP first recommendation. bcrypt remains the right choice when you need compatibility with existing hashes (Rails Devise, Laravel's default driver, ASP.NET Identity, Active Directory bridges, PHP's password_hash() legacy schemas). This tool is for the "we already have bcrypt and need to keep it honest" reality, not the "what should we pick fresh" question.
📚 Fun Facts
The number you store in $2b$NN$ is not the round count itself — it is the log₂ of the round count. Cost 12 means 4,096 rounds, cost 13 means 8,192, cost 31 (the theoretical maximum) would mean 2,147,483,648 rounds. That logarithmic encoding is why the spec only needs two characters for the cost field while still giving you a thousand-fold range.
The 2a, 2b, 2x, 2y prefixes you see in the wild are not algorithm variants but bug-fix generations. $2a$ was the 1999 OpenBSD original; $2x$ and $2y$ are PHP-specific markers from a 2011 Crypt_Blowfish wrap-around fix; $2b$ is the modern, spec-correct prefix you should be generating today. Most validators accept all four for backward compatibility, but new hashes you produce — including the prefix this tool builds — use $2b$.