Password hashing is one of the few areas where the correct answer is short and the wrong answers are all variations on the same mistake.
Use a slow hash
Or bcrypt, which is older and fine:
Both generate a salt automatically and store it inside the hash string. You don't manage it and you shouldn't try.
Why not SHA-256
Because it's fast, and that's a design goal for a general-purpose hash and a defect for a password one. Commodity hardware computes billions of SHA-256 hashes per second, so a leaked database of SHA-256 password hashes is a list of passwords in a few hours.
Argon2 and bcrypt are deliberately slow and memory-hungry. The cost is a few hundred milliseconds per login for you, and the difference between hours and centuries for someone with the database.
Adding a salt to SHA-256 doesn't fix this. Salts prevent precomputed rainbow tables; they don't slow down brute force against a single hash.
Don't encrypt
Encryption is reversible by design, which means a key exists, which means the key can leak alongside the data. Hashing has no key and no reverse. You never need to read a password back. You only need to check whether an attempt matches.
Cost factor
Use the library default and revisit it occasionally. Hardware gets faster, so a cost that was reasonable in 2015 isn't now. Rough target: 200–500ms per hash on your production hardware, tuned by measuring rather than guessing.
The surrounding bits
Don't cap length low. A 72-character bcrypt limit is real; a 16-character limit is a sign the password is being stored somewhere it shouldn't be.
Rate limit login. Slow hashing protects you after a database leak. It does nothing about someone trying common passwords against your live login endpoint. Auth routes without throttling were one of the recurring findings across the 24 AI-generated applications we scanned.
Check against known breaches. Have I Been Pwned's range API lets you check a password against breached sets without sending it, you send the first five characters of the hash and match locally.
Same response for wrong user and wrong password. Different messages tell an attacker which accounts exist.
Better still, don't store them
Passwords you don't hold can't leak. OAuth, passkeys or a managed auth provider removes this problem rather than solving it, and for most products that's the better trade.
If you are storing them, the code above is the whole answer. It's one of the few security problems with a settled solution.