TextDecoder
new TextDecoder(encoding) TextDecoder turns raw bytes into a JavaScript string. It is part of the Encoding API — the counterpart to TextEncoder. In browsers it lives on window; it also works in Web Workers. Every modern JavaScript environment supports it.
Constructor
new TextDecoder(encoding = "utf-8", options)
Parameters
encoding(string) — A valid WHATWG encoding label. Defaults to"utf-8". Case-insensitive, so"UTF-8"and"utf-8"work the same.options(object) — Optional configuration:fatal(boolean) — Whentrue,decode()throws aTypeErroron malformed bytes. Defaults tofalse(replaces bad bytes with the Unicode replacement characterU+FFFD).ignoreBOM(boolean) — Whentrue, skips the byte order mark. Defaults tofalse.
Throws
RangeErrorif the encoding label is not a recognized WHATWG label.
// Default UTF-8 decoder
const decoder = new TextDecoder();
// Decoder for a specific encoding
const latinDecoder = new TextDecoder("iso-8859-1");
// Strict decoder — throws on invalid bytes
const strictDecoder = new TextDecoder("utf-8", { fatal: true });
encoding
dec.encoding // "utf-8"
A read-only property that returns the name of the encoding the decoder is using. Note that encoding labels are normalized — creating a decoder with "UTF-8" still reports .encoding as "utf-8".
const dec = new TextDecoder("ISO-8859-1");
console.log(dec.encoding); // "windows-1252"
decode()
decode(buffer, options)
Parameters
buffer(ArrayBuffer | TypedArray | DataView) — The encoded byte data to decode.options(object) — Optional:stream(boolean) — Settruewhen decoding a chunk of a larger stream and more data will follow. Omit or setfalsefor the final chunk (or a complete buffer in one call).
Returns string — The decoded text.
Throws
TypeErroriffatal: truewas set and the buffer contains invalid data for the given encoding.
const bytes = new Uint8Array([72, 101, 108, 108, 111]);
const text = new TextDecoder().decode(bytes);
console.log(text); // "Hello"
Fatal mode
With fatal: true, malformed bytes cause an immediate error instead of silent substitution:
const bad = new Uint8Array([0x80]); // not valid UTF-8
// Default: replacement character inserted
const result = new TextDecoder().decode(bad);
console.log(result.length); // 1 — one U+FFFD character
// Strict: throws
try {
new TextDecoder("utf-8", { fatal: true }).decode(bad);
} catch (e) {
console.log(e instanceof TypeError); // true
}
Streaming decode
When processing data in chunks (for example, from a file or network stream), pass stream: true on all chunks except the last. This tells the decoder to hold state between calls instead of flushing after each chunk:
const chunks = [
new Uint8Array([0x48, 0x69]), // "Hi"
new Uint8Array([0x20, 0x74, 0x68]), // " th"
new Uint8Array([0x65, 0x72, 0x65]), // "ere"
];
const decoder = new TextDecoder();
let result = "";
for (const chunk of chunks) {
result += decoder.decode(chunk, { stream: true });
}
result += decoder.decode(); // final chunk — no buffer, stream: false by default
console.log(result); // "Hi there"
A common mistake is using stream: true on the final chunk. When you do that, the decoder waits for more data and returns an empty string. Always call decode() with no arguments (or stream: false) to flush the final chunk.
Common Gotchas
Default fatal: false silently replaces bad bytes. If you need strict validation, you must pass { fatal: true } to the constructor. Most developers never notice corrupted data because the replacement character looks like a normal character in casual inspection.
Encoding labels are normalized. The WHATWG spec maps many label aliases to canonical names. "utf-8" and "UTF-8" both produce a decoder with .encoding === "utf-8". Some legacy labels map to different encodings — "iso-8859-1" actually maps to "windows-1252".
BOM is always skipped. The UTF-8 byte order mark (0xEF 0xBB 0xBF) does not appear in the output regardless of how you set ignoreBOM. There is no option to include it.
stream: true on the final chunk returns an empty string. This trips up developers processing a fixed set of chunks — the last chunk should use decode() with no options or stream: false.
See Also
- TextEncoder — Encodes strings to UTF-8 bytes (the inverse operation)
- ArrayBuffer — The raw binary container you pass to
decode() - TypedArray — Typed array types used to represent the byte input
Written
- File: sites/jsguides/src/content/reference/built-in-objects/textdecoder.md
- Words: ~630
- Read time: 3 min
- Topics covered: constructor, encoding property, decode(), fatal mode, streaming decode, gotchas
- Verified via: https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder
- Unverified items: none