MD5 has an odd reputation. Half the internet will tell you never to touch it, the other half quietly uses it in a hundred internal tools every day. Both are right, depending on the job. The trick is knowing which situations are fine and which ones will get you a stern comment in code review — or worse, a security incident.

What MD5 actually is

MD5 (Message Digest 5) is a hash function that takes any input and produces a fixed 128-bit output, usually written as a 32-character hexadecimal string. The same input always produces the same output, and even a tiny change to the input scrambles the result completely.

md5("hello")       = 5d41402abc4b2a76b9719d911017c592
md5("hello.")      = 042ec14dc33e0e6ff8a4f8f2fd1eb2f2
md5("Hello")       = 8b1a9953c4611296a827abf8c47804d7

Notice how a single character or capitalisation change gives a totally different digest. That property — small input change, big output change — is called the avalanche effect, and it's the whole point of a hash.

It's a one-way function

You can't reverse an MD5 hash back into the original data. There's no decrypt button. What people call "cracking" MD5 is really just hashing lots of candidate inputs and comparing the results. That distinction matters when you're deciding what to use it for.

When MD5 is genuinely useful

Despite the warnings, MD5 is still a perfectly reasonable tool for a specific set of non-security tasks:

  • Checksums and integrity checks — verifying a file downloaded intact, or that a config blob hasn't changed accidentally.
  • Cache keys and deduplication — hashing a request payload or a chunk of content to produce a short, deterministic key.
  • Change detection — storing a hash of a record so you can tell if it's been modified without diffing every field.
  • Bucketing and sharding — hashing an ID to spread data evenly across partitions.

In all of these, you're relying on MD5 being fast and deterministic, not on it being cryptographically secure. That's exactly where it shines. It's also fast — noticeably quicker than SHA-256 — which is why it lingers in high-throughput code paths.

Where MD5 will bite you

Never use it for passwords

This is the big one. MD5 is far too fast, which means an attacker with a leaked hash table can try billions of guesses per second on commodity hardware. Storing passwords as plain MD5 — even with a salt — is negligent in 2024. Use a purpose-built password hash like bcrypt, scrypt, or Argon2, which are deliberately slow and memory-hard.

It's broken for security signatures

MD5 is vulnerable to collision attacks: researchers can craft two different inputs that produce the exact same hash. That completely undermines any use where you're trusting the hash to prove authenticity — digital signatures, certificate validation, verifying that a file came from who you think it did. If a hash collision would let an attacker substitute malicious content, MD5 is the wrong choice. Reach for SHA-256 instead.

Encoding and normalisation gotchas

Because MD5 hashes bytes, not "text", the same string can produce different hashes depending on encoding. UTF-8 versus UTF-16, a trailing newline, Windows CRLF versus Unix LF — all change the result.

md5("config\n")    // one hash
md5("config")      // completely different

If you're comparing hashes across systems, agree on encoding and trimming rules up front, or you'll spend an afternoon wondering why two identical-looking files don't match.

A short worked example

Say you're building a simple cache and want a stable key for an arbitrary request. In Node.js:

const crypto = require('crypto');

function cacheKey(payload) {
  const normalized = JSON.stringify(payload);
  return crypto
    .createHash('md5')
    .update(normalized, 'utf8')
    .digest('hex');
}

cacheKey({ user: 42, page: 2 });
// => 'a1f3...' (stable for identical objects)

One caveat worth flagging: JSON.stringify doesn't guarantee key order for objects built differently, so {a:1,b:2} and {b:2,a:1} can produce different strings and therefore different hashes. If that matters, sort the keys before stringifying.

In Python the equivalent is just as short:

import hashlib

def md5_hex(text: str) -> str:
    return hashlib.md5(text.encode('utf-8')).hexdigest()

md5_hex('hello')  # '5d41402abc4b2a76b9719d911017c592'

When you just need a one-off hash — checking a checksum from a download page, testing that your code produces the value you expect, or debugging why two hashes don't match — it's quicker to paste the string into a browser than to fire up a REPL. Our MD5 Hash Generator does exactly that, right in the page.

Quick decision guide

  • Verifying a non-adversarial download? MD5 is fine, though publishers increasingly ship SHA-256 too.
  • Building a cache key or dedup fingerprint? MD5 is a solid, fast choice.
  • Storing passwords? Never. Argon2 or bcrypt.
  • Signing or validating anything an attacker could tamper with? SHA-256 minimum.

The short version

MD5 isn't dead — it's just been demoted. Treat it as a fast fingerprinting tool for data you already trust, and keep it out of anything where an attacker benefits from forging a match. Get that boundary right and it'll keep quietly doing useful work in your codebase for years. Get it wrong and it becomes the line item in the post-incident report you don't want your name on.

When in doubt, ask yourself one question: would a collision or a fast brute-force actually help an attacker here? If yes, pick a stronger hash. If no, MD5's speed and ubiquity make it a perfectly pragmatic pick.

Photo by Chris Ried on Unsplash