Library / SDK
nodeca/pako avatar
nodeca/pako

pako: a zlib port in JavaScript for browsers and Node.js

high speed zlib port to javascript, works in browser & node.js

6,119 stars801 forksJavaScriptMIT

At a glance

What is it?
pako reimplements zlib's deflate and inflate in JavaScript, aiming for byte-identical gzip output and small browser bundles. Here is what it does well, where it falls short of native zlib, and how to install and use it.
Who is it for?
Adopt pako when you need gzip or deflate inside a browser bundle or a JavaScript runtime without native zlib, and when byte-identical output to zlib 1.3.2 matters. Do not adopt it if you need the full zlib C API surface (deflateCopy, deflateBound, inflateSync and the rest are documented as absent), or if raw throughput is the deciding factor: the README's own benchmark shows inflate-zlib at 397 ops/sec against inflate-pako at 138 ops/sec on a 1 MB sample under node v24.
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 18 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 September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What problem pako solves, and who it is for

JavaScript environments historically had no built-in gzip. Node.js exposes zlib through a native binding, but browsers do not, and neither do many embedded JavaScript runtimes. pako fills that gap by porting zlib's deflate and inflate algorithms to JavaScript so the same compression code runs in a browser, in Node.js, and in bundlers that target either. The README describes it as "very fast zlib-compatible compression for JavaScript" and states that the full minified browser bundle is under 15K gzipped, with deflate-only and inflate-only builds smaller still. That size claim is the reason many people reach for it: a page that needs to decompress a gzip payload should not have to ship a compression library's deflate half. The package is published to npm as pako, version 3.0.2 in the manifest shown here, and it exposes separate entry points for the full API, deflate-only, and inflate-only browser builds. The audience is front-end engineers handling gzipped assets or compressed API payloads, Node developers who want one compression path across server and client, and anyone porting code that already speaks zlib's format.

How pako's deflate and inflate pipeline is put together

pako mirrors zlib's two-stage design. Deflate takes input, runs it through an LZ77-style match finder, then Huffman-codes the result into a deflate stream wrapped in either zlib or gzip headers. Inflate reverses that: header parse, Huffman decode, back-reference copy. The README's headline compatibility claim is that pako "can produce the same deflate/gzip bytes as original zlib (1.3.2) and Node.js' patched zlib", which matters when compressed output is hashed, cached, or compared across services. The source tree keeps the ported C code in /src/zlib, separate from the rest of src/, and the package's licence field reflects that split: "(MIT AND Zlib)". Two interfaces are documented. The high-level helpers deflate() and inflate() take a whole buffer and return a whole buffer, and the README notes that inflate "can throw exception on broken stream". The streaming classes Deflate and Inflate use push() calls, expose err and msg instead of throwing, and accumulate output in result. That second interface is the one to use for chunked network data, where a truncated or corrupt stream should surface as a flag rather than an exception. The README also states that high-level wrappers "may not support some flush modes", so code that depends on precise flush behaviour should go through the class interface.

Installing pako and compressing a payload for the first time

The README gives one install command, and the package ships only dist/ per the files field in package.json. After installing, the fastest way to see it work is the high-level deflate helper, which detects the input type and recodes strings to UTF-8 before compressing.

bash
npm install pako

A first round trip: stringify an object, deflate it, inflate it back, and ask the inflate helper to decode the UTF-8 for you. The README's own example follows this shape, using deflate(JSON.stringify(test)) and then inflate(compressed, { toText: true }).

javascript
import { deflate, inflate } from 'pako';

const test = { my: 'super', puper: [456, 567], awesome: 'pako' };
const compressed = deflate(JSON.stringify(test));
const restored = JSON.parse(inflate(compressed, { toText: true }));

If your code is CommonJS, the README shows the same functions via require, and a namespace import is available when you want the whole API as one object.

javascript
const { deflate, inflate } = require('pako');

For browser work, the package map exposes ./browser, ./browser/deflate and ./browser/inflate, so a bundler can pick the minified ESM or UMD build without pulling in both halves. The README points to https://unpkg.com/pako@latest/ for inspecting the dist/ contents before you commit to a build configuration.

Where pako falls short of real zlib

The README is unusually direct about missing API. On the deflate side it lists deflateCopy, deflateBound, deflateParams, deflatePending, deflatePrime and deflateTune as absent. On the inflate side it lists inflateCopy, inflateMark, inflatePrime, inflateGetDictionary, inflateSync, inflateSyncPoint and inflateUndermine. If your code calls inflateSync to recover a partially corrupted stream, or deflateBound to size an output buffer ahead of time, pako will not compile against that call. This is a port of the algorithm, not a drop-in replacement for the C library's full surface. The second limitation is speed, and the project publishes its own numbers rather than hiding them. On a 1 MB sample under node v24, the README's benchmark shows deflate-zlib at 30.30 ops/sec against deflate-pako at 14.27 ops/sec, and inflate-zlib at 397 ops/sec against inflate-pako at 138 ops/sec. The README's claim that performance is "comparable with native zlib in modern JavaScript engines" is therefore generous: inflate runs at roughly a third of the native rate in that table. In a browser there is no native zlib to compare against, so the comparison is moot there, but in Node.js, where zlib is built in, pako is the slower option and you should have a reason to choose it, such as a shared code path between server and client. A third constraint is flush behaviour: the README states that high-level wrappers may not support some flush modes, which can matter in streaming protocols that rely on a flush to force buffered data out.

pako versus Node's built-in zlib module

The obvious alternative in Node.js is the zlib module itself, which wraps the native library and is the source of the 30.30 and 397 ops/sec figures in pako's own benchmark table. The difference is not just speed, it is where the code runs. Node's zlib is unavailable in a browser, so a project that compresses on the client and again on the server needs either two implementations or one portable one. pako is the portable option, and its byte-equivalence claim is what makes that choice safe: if the browser produces the same gzip bytes as the server's zlib, cached responses and content hashes stay consistent across both. Node's zlib also exposes the full C API, including the functions pako lists as missing, so code that needs deflateBound or inflateSync has no reason to switch. The practical split is therefore by environment, not by preference: use the built-in module on the server unless you specifically need output that matches a browser bundle byte for byte, and use pako where no native zlib exists or where one code path is worth the throughput cost.

Maintenance status, licence split and upgrade cost

The repository is not archived, and the last push was on 2026-09-12, which is recent. The manifest shows version 3.0.2 with a main field pointing at ./dist/pako.cjs.js and a module field at ./dist/pako.mjs, so both module systems are covered by the published artifact. Only dist/ is included in the npm package, which means consumers never see src/ and cannot patch the ported zlib code in place. The licence is the part worth reading twice. The README states MIT for all files except the /src/zlib folder, which is ZLIB, and package.json records this as "(MIT AND Zlib)". Both are permissive, but they are two different licences applying to different parts of the tree, and the combined SPDX expression is what tooling will report. If your organisation requires a single licence identifier, or if you redistribute a modified build, check how the ZLIB-licensed portion is handled before you ship. This is a description of what the repository states, not legal advice. On upgrade cost, the split entry points under exports (., ./browser, ./browser/deflate, ./browser/inflate) mean a major version can change which file a bundler resolves without changing your import statement, so pin the version and read CHANGELOG.md before moving across a major boundary.

Editorial conclusion

Adopt pako when you need gzip or deflate inside a browser bundle or a JavaScript runtime without native zlib, and when byte-identical output to zlib 1.3.2 matters. Do not adopt it if you need the full zlib C API surface (deflateCopy, deflateBound, inflateSync and the rest are documented as absent), or if raw throughput is the deciding factor: the README's own benchmark shows inflate-zlib at 397 ops/sec against inflate-pako at 138 ops/sec on a 1 MB sample under node v24. Before committing, verify that the flush modes your pipeline uses are supported by the high-level wrappers, and check the /src/zlib ZLIB licence terms against your distribution requirements.

Frequently asked questions

How do I install pako?

The README gives a single command, npm install pako, and the published package contains only the dist/ folder. Both ESM and CommonJS entry points are declared in package.json, so the same install works for import and require.

Does pako produce the same output as zlib?

The README states that pako can produce the same deflate and gzip bytes as original zlib 1.3.2 and Node.js' patched zlib. That byte equivalence is the project's headline compatibility claim.

Which zlib functions does pako not implement?

The README lists deflateCopy, deflateBound, deflateParams, deflatePending, deflatePrime and deflateTune as missing on the deflate side, and inflateCopy, inflateMark, inflatePrime, inflateGetDictionary, inflateSync, inflateSyncPoint and inflateUndermine as missing on the inflate side.

Can pako handle chunked or streaming data?

Yes. The README documents Deflate and Inflate classes with push() calls, where the last deflate chunk is marked with true, errors are reported through the err and msg properties instead of exceptions, and output collects in result.

What licence does pako use?

The README says MIT for all files except the /src/zlib folder, which is ZLIB, and package.json records the combination as "(MIT AND Zlib)". Both are permissive, but they apply to different parts of the tree.

Official sources

  1. Issues
  2. License: MIT
  3. nodeca/pako on GitHub
  4. Project website
  5. README
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/nodeca-pako.svg)](https://hysenlabs.com/projects/nodeca-pako)