# js-md5 gives you MD5 in the browser, in Node, and as a typed module

> js-md5 is a small JavaScript MD5 implementation with UTF-8 support, one-shot and streaming APIs, HMAC, several output formats and four build variants. It is a hashing utility for checksums and cache keys, and the README says nothing about using it for passwords or signatures.

**emn178/js-md5** — A simple MD5 hash function for JavaScript supports UTF-8 encoding.

- Repository: https://github.com/emn178/js-md5
- Stars: 837 · Forks: 421
- Language: JavaScript
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/emn178-js-md5

## A checksum utility, with a security question it never answers

js-md5 describes itself as a simple and fast MD5 hash function for JavaScript that supports UTF-8 encoding, and the repository description says the same. That is the entire scope, and it is worth being blunt about what that scope means for an evaluation.

The project ships no password hashing helpers, no key derivation, no constant time comparison and no argument about digest strength. The README documents an MD5 function, an HMAC function built on MD5, and a set of output formats. Nothing in the documentation claims the digest is fit for password storage, signature verification or any other security property, and the API surface gives you no way to configure a work factor or a cost.

Where it does earn its place is the long tail of ordinary hashing needs. Comparing two payloads for equality without shipping megabytes of content, deriving a stable identifier from a string for a cache key, producing a checksum to display next to a downloaded file, or fingerprinting a blob so you can skip a redundant upload. The library also provides a streaming interface for the case where the input is larger than you want to hold in one string.

The author is listed as Chen, Yi-Cyuan, and the project is released under the MIT license.

## One-shot calls and incremental hashing over the same object

The API has two levels. The short form hashes a value and returns the digest directly, and the README gives the empty string and the quick brown fox sentence as worked examples with their expected digests.

```js
md5(''); // d41d8cd98f00b204e9800998ecf8427e
md5('The quick brown fox jumps over the lazy dog'); // 9e107d9d372bb6826bd81d3542a419d6
md5('The quick brown fox jumps over the lazy dog.'); // e4d909c290d0fb1ca068ffaddf22cbd0
```

For larger input, the create form returns an object you feed with update calls and then ask for the result.

```js
md5('Message to hash');
var hash = md5.create();
hash.update('Message to hash');
hash.hex();
```

The same two level shape applies to HMAC, where the key becomes the first argument in the one-shot form and the key argument of create.

```js
// HMAC
md5.hmac('key', 'Message to hash');

var hash = md5.hmac.create('key');
hash.update('Message to hash');
hash.hex();
```

Note the HMAC one-shot call in the README returns the same kind of value as the plain one-shot call, while the named variants below return specific formats, so the output type depends on which function you call rather than on a shared option object. That asymmetry is easy to get wrong when you switch between a one-shot call and a streaming call in the same codebase.

## Four output formats, and one of them is on its way out

Digest output is not a single shape here. The README lists hex, array, digest, arrayBuffer and base64, each with its own example.

```js
// Different output
md5(''); // d41d8cd98f00b204e9800998ecf8427e
md5.hex(''); // d41d8cd98f00b204e9800998ecf8427e
md5.array(''); // [212, 29, 140, 217, 143, 0, 178, 4, 233, 128, 9, 152, 236, 248, 66, 126]
md5.digest(''); // [212, 29, 140, 217, 143, 0, 178, 4, 233, 128, 9, 152, 236, 248, 66, 126]
md5.arrayBuffer(''); // ArrayBuffer
md5.base64(''); // 1B2M2Y8AsgTpgAmY7PhCfg==
```

The array and digest forms return the same byte array here, base64 returns a string encoding of the same digest, and arrayBuffer returns a binary buffer.

One of these has a deprecation notice attached. The README states that the buffer method is deprecated, that this may be confused with Buffer in node.js, and that you should use arrayBuffer instead. That is a small but real migration item: if you are upgrading from an older version of this library, any call to md5.buffer has to change, and the replacement is not a straight rename because the return type changes with it.

The input side is equally permissive. The README shows that md5 accepts strings including UTF-8 text, byte arrays, Uint8Array and ArrayBuffer.

```js
// It also supports UTF-8 encoding
md5('中文'); // a7bac2239fcdcb3a067903d8077c4a07

// It also supports byte `Array`, `Uint8Array`, `ArrayBuffer`
md5([]); // d41d8cd98f00b204e9800998ecf8427e
md5(new Uint8Array([])); // d41d8cd98f00b204e9800998ecf8427e
```

## The builds table decides what you can use in old browsers

Rather than shipping one artifact, the project ships several, and the README includes a table comparing them across five dimensions: legacy fallbacks, node acceleration, HMAC, Base64 and the deprecated buffer method.

The full build, md5.js and md5.min.js, is the only one with legacy fallbacks enabled, and it keeps everything including HMAC, base64 and the deprecated buffer method. The modern build, md5.modern.js and md5.modern.min.js, drops the legacy fallbacks but keeps node acceleration, HMAC, base64 and the deprecated method. The lite build, md5-lite.js and md5-lite.min.js, drops legacy fallbacks and node acceleration and removes HMAC and base64 as well, while still exposing the one-shot and streaming APIs with hex, array, digest and arrayBuffer output.

The cost of the lite build is therefore concrete. If you pick md5-lite.js and then need an HMAC or a base64 digest, the function is not there. The reason it exists is stated right after the table: the modern and lite builds require Array.isArray, ArrayBuffer, typed arrays and ArrayBuffer.isView, so any environment without those features needs the legacy build instead.

The download section links each artifact directly, including an uncompressed source at src/md5.js, so you can vendor a single file into a page with no package manager at all.

## Installing by npm, by bower, or by copying one file

For Node the project documents an npm install, and the README also mentions bower as an option.

```bash
npm install js-md5
```

```bash
bower install md5
```

The import styles differ by environment, which is the part that trips people up when they move a script between a bundler and a plain Node file. In Node the module is required, and in TypeScript it is imported by name.

```js
var md5 = require('js-md5');
```

```ts
import { md5 } from 'js-md5';
```

There is also AMD support for RequireJS users.

```js
require(['your/path/md5.js'], function(md5) {
// ...
});
```

The package.json explains the resolution rules. The main field points at src/md5.js, the module field at build/md5.mjs, and the exports map lists a node condition that prefers build/md5.node.mjs for import and src/md5.js for require, with the browser import resolving to build/md5.mjs and the default falling back to src/md5.js. Many individual build paths are exported by name, including every modern and lite variant and their minified and mjs forms, so a consumer can pin an exact artifact.

The scripts show how the project itself is verified: mocha under nyc for the Node tests, then a build test and an ESM test, with rollup and terser as the build tooling and jsdoc for the documentation in the doc directory.

## Where js-md5 is the wrong choice

Two boundaries stand out. The first is cryptographic strength, which the project never claims and does not address in the documentation. If your requirement is to resist guessing or tampering, an MD5 digest is the wrong primitive and nothing in this library changes that. The HMAC function here inherits the same weakness, because an HMAC built on MD5 is only as strong as the underlying digest.

The second boundary is the browser support floor for the modern and lite builds. If you still target an environment without typed arrays, you are pushed back to the legacy build, and the legacy build is the one that still carries the deprecated buffer method and the legacy fallbacks. That is a maintenance and audit cost rather than a functional one.

On performance, the project publishes a set of benchmark links covering short strings, long strings, very long strings and an async variant, and it notes in the README that js-md5 is the fastest synchronous MD5 library but slower than Hash-WASM. That comparison is the practical alternative to weigh. Hash-WASM moves the hashing work into WebAssembly, and the benchmark list in this project includes both measurethat.net and jsperf.app entries so you can compare both approaches on the same input rather than trusting the claim in the README. The project also points to file benchmark issues in its tracker, which is where hashing large files is discussed separately from string hashing.

If you only need a checksum, the platform itself may already be enough. The browser has the SubtleCrypto API and Node has the built-in crypto module, so adding a dependency is only worth it when you specifically want this library's API shape, its four output formats or its build variants.

## Conclusion

js-md5 fits browser and Node code that needs a deterministic checksum, a cache key, a deduplication fingerprint or an HMAC over UTF-8 text, and it fits projects that need the library without a build step through the UMD file in build/. It does not fit work that requires cryptographic strength, and it does not fit browser projects that still support environments without typed arrays, where the md5-lite.js build drops the features you would otherwise want. Before adopting, check that md5.buffer is not in your existing call sites since it is deprecated in favour of md5.arrayBuffer, decide whether the lite build's missing HMAC and base64 output matters, and confirm the package.json exports map resolves the build variant your bundler expects, because the entry point differs between CommonJS, ESM and Node specific files.

## FAQ

### How do I install and use js-md5 in Node.js?

Run npm install js-md5, then require the module with var md5 = require('js-md5'); and call md5('Message to hash'). In TypeScript the import form is import { md5 } from 'js-md5';.

### Does js-md5 support UTF-8 and binary input?

Yes. The README documents that it supports UTF-8 encoding, with md5('中文') given as an example, and it also accepts byte Array, Uint8Array and ArrayBuffer values as input.

### What is the difference between md5, md5.modern and md5-lite?

The full md5.js build keeps legacy fallbacks, node acceleration, HMAC, Base64 and the deprecated buffer method. The modern build drops the legacy fallbacks but keeps the rest. The lite build drops legacy fallbacks and node acceleration and also removes HMAC and Base64, while keeping the one-shot and streaming APIs with hex, array, digest and arrayBuffer output.

### Why was the buffer method deprecated in js-md5?

The README states that the buffer method is deprecated because it may be confused with Buffer in node.js, and that you should use arrayBuffer instead. Any existing call to md5.buffer has to change, and the return type changes with it.

### Can js-md5 compute HMAC values?

Yes, through md5.hmac and md5.hmac.create. The one-shot form takes a key and a message, for example md5.hmac('key', 'Message to hash'), and there are named variants such as md5.hmac.hex and md5.hmac.array. HMAC is not available in the lite build.

### How does js-md5 compare with Hash-WASM?

The README notes that js-md5 is the fastest synchronous MD5 library but slower than Hash-WASM, and it links benchmark pages on measurethat.net and jsperf.app for short, long and very long strings plus an async variant. Hash-WASM performs the hashing in WebAssembly, which is the architectural difference behind that result.

## Sources

- [emn178/js-md5 on GitHub](https://github.com/emn178/js-md5)
- [Issues](https://github.com/emn178/js-md5/issues)
- [License: MIT](https://github.com/emn178/js-md5/blob/master/LICENSE)
- [README](https://github.com/emn178/js-md5/blob/master/README.md)
- [Releases](https://github.com/emn178/js-md5/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/emn178-js-md5
