Library / SDK
pillarjs/iconv-lite avatar
pillarjs/iconv-lite

iconv-lite: pure JavaScript encoding conversion, and what the 1.0 alpha changes

Convert character encodings in pure javascript.

3,180 stars296 forksJavaScriptMIT

At a glance

What is it?
iconv-lite converts character encodings without native compilation, which is why body parsers and mail libraries depend on it. The 1.0 alpha line is a separate, Node 22 only track, and the README is explicit that UTF-7 is not for bulk text.
Who is it for?
Adopt iconv-lite when you need encoding conversion in JavaScript without a compiler toolchain, or when your input is a legacy singlebyte or CJK multibyte encoding such as win1251, GB18030 or Shift_JIS. Do not adopt it for transliteration, since the README states that untranslatable characters become the replacement character or a question mark and that no transliteration is supported, and do not use UTF-7 for large text.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 31 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 2, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem iconv-lite removes: encoding conversion without a C compiler

Most encoding conversion in Node.js has historically gone through node-iconv, which binds to the system libiconv. That works until it does not: the build needs a compiler and headers on the machine, which is awkward on Windows, in serverless runtimes, and in sandboxed or browser-targeted bundles. iconv-lite exists to remove that step. The README's first bullet is exactly this: no need for native code compilation, quick to install, works on Windows, Web, and in sandboxed environments.

The audience follows from that constraint rather than from a feature list. If you are writing an HTTP body parser that must handle a charset header, a mail library that reads headers encoded in odd charsets, or a data import path that receives files from Windows systems, you need conversion to work on whatever machine runs your code. iconv-lite is also used in the browser through browserify or webpack, at roughly 180kb gzip compressed with the Buffer shim included, and React Native is supported if the stream module is installed to enable the Streaming API. Those are the two places a libiconv binding cannot go.

How the conversion actually works: tables, streams and BOM rules

The library is a set of generated lookup tables plus a small decode/encode core. The repository layout shows this directly: encodings/, generation/, lib/ and backends/ sit at the top level, and generation/ is what produces the tables. The README states that most singlebyte encodings are generated from node-iconv, while multibyte encodings are generated from Unicode.org mappings and WHATWG Encoding Standard mappings. So the singlebyte tables inherit libiconv's behaviour, and the multibyte ones follow the WHATWG spec, which is the same reference browsers use.

Coverage is broad and stated plainly: all Node.js native encodings (utf8, ucs2 / utf16-le, ascii, binary, base64, hex), extra Unicode encodings (utf16, utf16-be, utf-7, utf-7-imap, utf32, utf32-le, utf32-be), the widespread singlebyte families (Windows 125x, ISO-8859, IBM/DOS codepages, Macintosh, KOI8) and the widespread multibyte ones (CP932, CP936, CP949, CP950, GB2312, GBK, GB18030, Big5, Shift_JIS, EUC-JP). Aliases such as latin1 and us-ascii are accepted, and encodingExists() lets you test a name before you commit to it.

The part that causes the most support questions is BOM handling, and the README is unusually specific here. On decode, a BOM is stripped by default unless you pass stripBOM: false, and stripBOM can also be a callback that fires only if a BOM was actually found. On encode, no BOM is added unless you pass addBOM: true. UTF-16 and UTF-32 add a second layer: the plain utf16 and utf32 names use BOM plus a spaces heuristic to guess endianness, defaulting to little endian, overridable with defaultEncoding: 'utf-16be' or 'utf-32be'. If you want that guessing out of your pipeline, name the explicit variant instead. The README also points to node-autodetect-decoder-stream for detecting a UTF-8 BOM while decoding another encoding, which is a fair admission that detection is not this library's job.

Installing iconv-lite from npm and decoding your first Buffer

The package is published on npm as iconv-lite, so installation is a normal npm install with no build step and no postinstall compilation. The current published line is 0.7.3, with 1.0.0-alpha.2 available as a prerelease.

bash
npm install iconv-lite

The README's basic API is three calls. decode takes a Buffer and an encoding name and returns a JavaScript string; encode goes the other way; encodingExists answers whether a name is known. Note the README's warning that decode() must be given a Buffer, otherwise, in its words, bad things usually happen.

javascript
var iconv = require('iconv-lite');

str = iconv.decode(Buffer.from([0x68, 0x65, 0x6c, 0x6c, 0x6f]), 'win1251');
buf = iconv.encode("Sample input string", 'win1251');
iconv.encodingExists("us-ascii")

If your input arrives as a stream rather than a Buffer, the streaming API is the one to reach for. The README shows a decode stream piped from an HTTP request, and a file conversion that decodes win1251 and re-encodes as ucs2 in a single pipeline.

javascript
fs.createReadStream('file-in-win1251.txt')
    .pipe(iconv.decodeStream('win1251'))
    .pipe(iconv.encodeStream('ucs2'))
    .pipe(fs.createWriteStream('file-in-ucs2.txt'));

Every encode and decode stream also carries a .collect(cb) method that accumulates the whole result, which the README demonstrates on a request body and which is the shortest path from a raw request to a complete string.

UTF-7 is supported but the README tells you not to use it for bulk text

The most useful limitation in the documentation is one the project states about itself. UTF-7 and UTF-7-IMAP (Modified UTF-7, RFC 3501) are supported, but the README says UTF-7 is designed for short, 7-bit-safe strings such as mail headers and IMAP mailbox names, and is not recommended for large or bulk text, where native utf8 and utf16 are faster. That is a clear boundary: if you are converting a multi-megabyte file, UTF-7 is the wrong choice even though the encoder will accept it.

The decode side of UTF-7 is also deliberately lenient. Ill-formed input, including an incomplete code unit, non-zero Base64 padding bits, a shift-in not followed by Base64 or a hyphen, or a non-ASCII byte outside a shifted run, is replaced with the replacement character. The fatal decode option is not supported for UTF-7, because RFC 2152 does not define it, so you cannot make UTF-7 decoding throw on bad input. If your pipeline depends on strict failure rather than silent replacement, UTF-7 cannot give you that.

The broader limitation is transliteration. The README states that untranslatable characters are set to the replacement character or a question mark, and that no transliteration is currently supported. So converting a Cyrillic string into a singlebyte encoding that lacks those glyphs does not produce a readable approximation; it produces markers. The UTF-32 decoder is stricter than the general path: per the Unicode Standard, surrogate code points, values above U+10FFFF, and truncated trailing code units are replaced with the replacement character, and fatal: true makes those throw instead. Encoding replaces a lone unpaired surrogate with the replacement character so the output stays valid UTF-32.

The 1.0 alpha is a different package for a different runtime

The release list shows two parallel tracks: 0.7.3 and 1.0.0-alpha.2, both published on 2026-07-03, with 1.0.0-alpha.1 earlier in 2026. The package.json for 1.0.0-alpha.2 sets engines.node to >=22, and the files field ships backends/, lib/, encodings/ and types/, with main pointing at ./lib/index-node.js. The presence of a backends/ directory and a test:node-web script that runs mocha with a web backend environment suggests the 1.0 line is reorganising how the Node and web builds are selected, rather than adding new encodings.

That matters for adoption decisions. If your runtime is Node 22 or newer and you want to track the next major, the alpha is installable, but it is an alpha: the version string itself is the warning. If you are on an older Node, the engines field rules the 1.0 line out and 0.7.3 is the version to pin. The repository's last push was on 2026-09-01, so work is ongoing, but the published stable line remains 0.7.x while 1.0 sits in prerelease.

Licence is MIT, declared in both the README badge and package.json. That is permissive and imposes no copyleft obligation on your own code, but the encodings themselves are generated from other sources: node-iconv for singlebyte tables, and Unicode.org and WHATWG mappings for multibyte ones. The README credits those authors. If your organisation audits data provenance rather than just code licences, that generation step is the thing to look at, and the generation/ directory is where it lives. This is not legal advice; check with your own counsel.

Where iconv-lite is the wrong tool, and what to use instead

iconv-lite is the wrong tool when you need transliteration, when you need strict failure on malformed UTF-7, or when you need an encoding outside its generated set. The README points to the wiki page listing all supported encodings, which is the authoritative check before you commit to a charset name. If your charset is not there, the library will not invent it.

The natural alternative is node-iconv, the libiconv binding the project compares itself against. The difference is architectural, not cosmetic. node-iconv calls into the system libiconv, so it can expose whatever encodings that library was built with, and it requires a native build. iconv-lite ships generated tables in JavaScript, so it installs anywhere JavaScript runs but is limited to the encodings its generators cover. The README's own performance table, measured on an old Node version against iconv 2.1.4, shows iconv-lite at roughly 320 Mb/s encoding and 246 Mb/s decoding for win1251 against roughly 96 and 95 Mb/s for node-iconv, with the caveat that results vary and should be checked on your own hardware. Treat those numbers as the project's claim from its own README, not as a current benchmark.

For browser-side decoding of a specific charset, the WHATWG TextDecoder API is another route, and it is the same specification that iconv-lite's multibyte tables are generated from. The trade-off is that TextDecoder's supported label set is whatever the browser implements, while iconv-lite gives you one consistent table set across Node, the browser and React Native.

Editorial conclusion

Adopt iconv-lite when you need encoding conversion in JavaScript without a compiler toolchain, or when your input is a legacy singlebyte or CJK multibyte encoding such as win1251, GB18030 or Shift_JIS. Do not adopt it for transliteration, since the README states that untranslatable characters become the replacement character or a question mark and that no transliteration is supported, and do not use UTF-7 for large text. Before installing, check the package.json engines field: the 1.0.0-alpha.2 release requires Node >=22, so a project on an older runtime has to stay on the 0.7.x line.

Frequently asked questions

What is iconv-lite?

It is a pure JavaScript character encoding conversion library published on npm as iconv-lite. It decodes Buffers into strings and encodes strings into Buffers across Node.js native encodings, singlebyte families such as Windows 125x and ISO-8859, and multibyte encodings such as GB18030, Big5 and Shift_JIS.

How do I install iconv-lite and decode a Buffer with it?

Install it from npm, then require it and call decode with a Buffer and an encoding name. The README's basic example decodes a Buffer with the win1251 encoding, and it warns that decode() must be given a Buffer or bad things usually happen.

Which Node version does iconv-lite 1.0 need?

The package.json for 1.0.0-alpha.2 sets engines.node to >=22. The 0.7.3 release is the current stable line published alongside it, so a project on an older runtime has to stay on 0.7.x.

Does iconv-lite strip or add a byte order mark?

On decoding, a BOM is stripped by default unless you pass stripBOM: false, and stripBOM can also be a callback that runs only if a BOM was found. On encoding, no BOM is added unless you pass addBOM: true.

Can iconv-lite transliterate characters that the target encoding cannot represent?

No. The README states that untranslatable characters are set to the replacement character or a question mark, and that no transliteration is currently supported.

Official sources

  1. Issues
  2. License: MIT
  3. pillarjs/iconv-lite on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pillarjs-iconv-lite.svg)](https://hysenlabs.com/projects/pillarjs-iconv-lite)