You're importing pako to gzip data. CompressionStream does it natively.
pako is one of npm's most downloaded packages — pulled in by thousands of projects to compress data before storing or sending it. CompressionStream and DecompressionStream do the same job natively, in any modern browser and Node.js 18+, with no dependencies and native C-speed execution.

Compressing data before writing it to IndexedDB or sending it over a slow connection is a real optimization. When a cached API response is too large for reliable storage, or when you need to shrink a JSON payload before POSTing it, pako.gzip() is the standard reach. But pako is a pure-JavaScript port of zlib — written in user space to fill a gap the browser had at the time. The CompressionStream API is that gap closing.
CompressionStream is a transform stream — data goes in one end, compressed data comes out the other. The constructor takes a format string: 'gzip', 'deflate', or 'deflate-raw'.
DecompressionStream is the mirror:
The Streams plumbing to feed data in and collect it out is the verbose part. Wrap it once:
Blob.stream().pipeThrough() feeds the data into the transform stream; new Response(stream) collects the result. The idiom is three lines of plumbing written once, then call sites that read plainly.
A direct swap for the most common pako usage patterns:
The output is the same gzip-format Uint8Array. Any system that accepts pako's output accepts the native output — the wire format is identical.
Storing large JSON in IndexedDB:
A 200 KB JSON object typically compresses to 15–30 KB with gzip. For quota-constrained storage like IndexedDB on mobile browsers, that difference matters.
Compressing in a Web Worker:
CompressionStream works in Web Workers and Service Workers — the same API, the same two-function wrapper, no restrictions. Offloading compression to a worker keeps the main thread free.
The three supported formats map directly to pako's methods:
CompressionStream format | pako equivalent | When to use |
|---|---|---|
'gzip' | pako.gzip / pako.ungzip | HTTP transport, file storage — the standard |
'deflate' | pako.deflate / pako.inflate | zlib-wrapped deflate |
'deflate-raw' | pako.deflateRaw / pako.inflateRaw | raw DEFLATE, no wrapper header |
'gzip' is the right default for most use cases. Use 'deflate-raw' only when interoperating with a system that expects unwrapped DEFLATE.
CompressionStream calls into the browser's native zlib implementation — the same C code path used when the browser decompresses HTTP responses with Content-Encoding: gzip. pako re-implements that algorithm in JavaScript. The native path is measurably faster on large inputs:
- For small payloads (< 10 KB), the difference is negligible.
- For large payloads (100 KB+), native compression is typically 3–10× faster than pako, because there's no JavaScript overhead and the engine can use SIMD instructions.
- There's also no bundle cost: pako adds ~45 KB minified to your bundle;
CompressionStreamadds zero.
CompressionStream and DecompressionStream are available in Node.js 18.0 as part of the Web Streams implementation. The two-function wrapper above works unchanged in Node 18+ — useful for isomorphic utilities that run in both browser and server environments without branching on the environment.
Node's older zlib module (zlib.gzipSync, zlib.gunzipSync) is still more ergonomic for Node-only server code. But if you're writing a shared utility that must work in both contexts, CompressionStream is the right choice.
CompressionStream is Baseline 2023: Chrome 80 (February 2020), Firefox 113 (May 2023), Safari 16.4 (March 2023), Node.js 18. The API has been in Chromium since early 2020; Firefox and Safari joined in 2023. It's available in all currently-supported browser and runtime versions, including Web Workers and Service Workers.
Runs right in your browser — poke at it and watch the concept react live.
Think it clicked? Take the 9-question quiz →
Instant feedback, a hint on every question, and an explanation for each answer — right or wrong.
Search your package.json for pako. If it's there and the use case is "compress a string or buffer before storing or sending it," the native API covers you. Replace pako.gzip and pako.ungzip with the two-function wrapper above, remove the dependency, and get native compression speed and zero bundle cost. The Streams API is verbose on its own — the wrapper absorbs that cost once so every call site stays clean.
Thanks for reading! Let's stay connected:
- ⭐ GitHub — follow me and star the projects: github.com/parsajiravand
- 💬 Discord — join the frontend best-practices community: discord.gg/d9KRhuAwQ
- 📸 Instagram — frontend best practices, daily: @bestpractice___
- 💼 LinkedIn — linkedin.com/in/parsa-jiravand
- ✉️ Email (work & contract inquiries): bestpractice2026@gmail.com
Originally published on dev.to