entities, he, and html-entities are npm packages designed to encode and decode HTML entities in JavaScript applications. They help safely handle user input, prevent XSS vulnerabilities, and ensure proper rendering of special characters like <, >, &, and non-ASCII symbols by converting them to or from their corresponding HTML entity representations (e.g., <, >, &). Each package offers slightly different APIs, performance characteristics, and feature sets for working with HTML entities in both browser and Node.js environments.
When you’re building web apps, you often need to convert special characters into safe HTML entities (like turning <script> into <script>) or decode them back for display. The three main libraries for this in the JavaScript ecosystem are entities, he, and html-entities. They all solve the same core problem but with different design philosophies, APIs, and trade-offs. Let’s compare them head-to-head.
All three packages support encoding (converting characters to entities) and decoding (converting entities back to characters), but their function signatures differ.
entities uses simple top-level functions:
import { encode, decode } from 'entities';
const encoded = encode('<div>Hello & "world"</div>');
// '<div>Hello & "world"</div>'
const decoded = decode('<div>Hello & "world"</div>');
// '<div>Hello & "world"</div>'
he also provides straightforward functions:
import * as he from 'he';
const encoded = he.encode('<div>Hello & "world"</div>');
// '<div>Hello & "world"</div>'
const decoded = he.decode('<div>Hello & "world"</div>');
// '<div>Hello & "world"</div>'
html-entities requires creating an instance first:
import { Html5Entities } from 'html-entities';
const entities = new Html5Entities();
const encoded = entities.encode('<div>Hello & "world"</div>');
// '<div>Hello & "world"</div>'
const decoded = entities.decode('<div>Hello & "world"</div>');
// '<div>Hello & "world"</div>'
💡 Note:
html-entitiesoffers separate classes likeXmlEntities,Html4Entities, andHtml5Entities, whileentitiesandhehandle standards via options or built-in logic.
How much control do you have over what gets encoded or decoded?
entities gives you granular control through options:
import { encode } from 'entities';
// Only encode non-ASCII characters
encode('café', { level: 'nonAscii' });
// 'café'
// Use XML-compatible encoding (no named entities)
encode('< &', { mode: 'xml' });
// '< &'
he focuses on strict HTML5 compliance but allows some decoding tweaks:
import * as he from 'he';
// Decode with strict mode (disallow ambiguous ampersands)
he.decode('AT&T', { strict: true });
// Throws error — 'AT&T' isn't a valid entity
// Default is lenient
he.decode('AT&T');
// 'AT&T'
html-entities lets you configure behavior at instantiation:
import { Html5Entities } from 'html-entities';
const entities = new Html5Entities({
level: 'all', // or 'basic', 'nonAscii'
encodeOptions: {
useNamedReferences: false,
decimal: true,
hexadecimal: false
}
});
entities.encode('©');
// '©' instead of '©'
This makes html-entities well-suited for scenarios where you reuse the same settings repeatedly—like in a server-rendered template engine.
Each library handles different sets of named entities:
entities supports XML, HTML4, and HTML5 via the mode option ('xml', 'html4', 'html5'). By default, it uses HTML5.he strictly implements the HTML5 spec, including obscure and legacy entities. It’s known for its completeness and correctness.html-entities provides distinct classes: XmlEntities (only <, >, etc.), Html4Entities, and Html5Entities, each with their own dictionary.For example, the euro symbol €:
// entities (default = HTML5)
encode('€'); // '€'
// he
he.encode('€'); // '€'
// html-entities (Html5Entities)
new Html5Entities().encode('€'); // '€'
But if you use XmlEntities from html-entities, it won’t use € (since XML doesn’t define it) and will fall back to numeric form if allowed.
entities is optimized for speed and small bundle size. It’s used internally by popular libraries like parse5 and cheerio. If you’re building a high-throughput SSR service or a static site generator, this is likely your best bet.he prioritizes spec compliance over raw speed. It’s slower than entities but more accurate in edge cases involving ambiguous or malformed entities. Great for parsers, validators, or data cleanup tools.html-entities trades a bit of performance for API flexibility. The class-based approach adds slight overhead but pays off when you need reusable, pre-configured encoders/decoders.How do they behave with malformed input?
entities decodes invalid entities as-is. decode('&xyz;') returns '&xyz;'.he does the same by default but can be set to strict mode to throw on invalid entities.html-entities always leaves unknown entities untouched—decode('&xyz;') → '&xyz;'.None of them attempt to “fix” broken markup beyond entity handling, which is correct behavior.
All three work in both environments. None rely on DOM APIs, so they run cleanly in Node.js, Web Workers, or edge runtimes like Cloudflare Workers.
| Feature | entities | he | html-entities |
|---|---|---|---|
| API Style | Functional | Functional | Class-based (stateful instances) |
| Standards Support | XML, HTML4, HTML5 (via mode) | HTML5 only (strictly compliant) | Separate classes per standard |
| Config Flexibility | High (per-call options) | Moderate (mainly for decoding) | High (per-instance config) |
| Performance | Fastest | Slower (accuracy-focused) | Moderate |
| Best For | SSR, sanitization, parsers | Spec-compliant tools, linters | Templating, reusable processors |
entities.he.html-entities’s instance-based API will feel natural.All three are actively maintained and production-ready—so your choice should hinge on your project’s architectural needs, not fear of obsolescence.
Choose entities if you need a fast, lightweight, and modern library that supports both encoding and decoding with fine-grained control over which character sets to process (e.g., XML, HTML4, HTML5). It’s ideal for performance-sensitive applications like SSR frameworks or sanitization pipelines where minimal bundle size and speed matter. Its API is clean and supports options like level and mode for precise behavior.
Choose he if you want a battle-tested, spec-compliant library that strictly follows the HTML5 standard for entity handling. It’s particularly strong in decoding accuracy and offers robust support for ambiguous ampersands and legacy named entities. Use it when correctness according to W3C specs is critical, such as in parsers, linters, or content migration tools.
Choose html-entities if you prefer an object-oriented API with separate encoder and decoder instances that can be pre-configured for repeated use. It supports multiple standards (XML, HTML4, HTML5) and allows toggling features like decimal/hex numeric encoding. This package suits applications needing reusable, stateful entity processors—like templating engines or rich text editors—where configuration reuse improves ergonomics.
Encode & decode HTML & XML entities with ease & speed.
entities is used by many popular libraries; eg.
htmlparser2, the official
AWS SDK and
commonmark use it to process
HTML entities.entities is the fastest library for decoding HTML entities (as of
September 2025); see performance.entitiesnpm install entities
entitiesconst entities = require("entities");
// Encoding
entities.escapeUTF8("& ü"); // "&#38; ü"
entities.encodeXML("& ü"); // "&#38; ü"
entities.encodeHTML("& ü"); // "&#38; ü"
// Decoding
entities.decodeXML("asdf & ÿ ü '"); // "asdf & ÿ ü '"
entities.decodeHTML("asdf & ÿ ü '"); // "asdf & ÿ ü '"
Benchmarked in September 2025 with Node v24.6.0 on Apple M2 using tinybench.
Higher ops/s is better; avg (μs) is the mean time per operation.
See scripts/benchmark.ts to reproduce.
| Library | Version | ops/s | avg (μs) | ±% | slower |
|---|---|---|---|---|---|
| entities | 7.0.0 | 5,838,416 | 175.57 | 0.06 | — |
| html-entities | 2.6.0 | 2,919,637 | 347.77 | 0.33 | 50.0% |
| he | 1.2.0 | 2,318,438 | 446.48 | 0.70 | 60.3% |
| parse-entities | 4.0.2 | 852,855 | 1,199.51 | 0.36 | 85.4% |
| Library | Version | ops/s | avg (μs) | ±% | slower |
|---|---|---|---|---|---|
| entities | 7.0.0 | 2,770,115 | 368.09 | 0.11 | — |
| html-entities | 2.6.0 | 1,491,963 | 679.96 | 0.58 | 46.2% |
| he | 1.2.0 | 481,278 | 2,118.25 | 0.61 | 82.6% |
| Library | Version | ops/s | avg (μs) | ±% | slower |
|---|---|---|---|---|---|
| entities | 7.0.0 | 4,616,468 | 223.84 | 0.17 | — |
| he | 1.2.0 | 3,659,301 | 280.76 | 0.58 | 20.7% |
| html-entities | 2.6.0 | 3,555,301 | 296.63 | 0.84 | 23.0% |
Note: Micro-benchmarks may vary across machines and Node versions.
What methods should I actually use to encode my documents?
If your target supports UTF-8, the escapeUTF8 method is going to be your best
choice. Otherwise, use either encodeHTML or encodeXML based on whether
you're dealing with an HTML or an XML document.
You can have a look at the options for the encode and decode methods to see
everything you can configure.
When should I use strict decoding?
When strict decoding, entities not terminated with a semicolon will be ignored. This is helpful for decoding entities in legacy environments.
Why should I use
entitiesinstead of alternative modules?
As of September 2025, entities is faster than other modules. Still, this is
not a differentiated space and other modules can catch up.
More importantly, you might already have entities in your dependency graph
(as a dependency of eg. cheerio, or htmlparser2), and including it directly
might not even increase your bundle size. The same is true for other entity
libraries, so have a look through your node_modules directory!
Does
entitiessupport tree shaking?
Yes! entities ships as both a CommonJS and a ES module. Note that for best
results, you should not use the encode and decode functions, as they wrap
around a number of other functions, all of which will remain in the bundle.
Instead, use the functions that you need directly.
This library wouldn't be possible without the work of these individuals. Thanks to
he, which was one of the inspirations
for entitiesparse5 projecthtml-entities library. entities
would be quite a bit slower if there wasn't any competition. Right now
entities is on top, but we'll see how long that lasts!License: BSD-2-Clause
To report a security vulnerability, please use the Tidelift security contact. Tidelift will coordinate the fix and disclosure.
entities for enterpriseAvailable as part of the Tidelift Subscription
The maintainers of entities and thousands of other packages are working with
Tidelift to deliver commercial support and maintenance for the open source
dependencies you use to build your applications. Save time, reduce risk, and
improve code health, while paying the maintainers of the exact dependencies you
use.
Learn more.