A CLI tool that downloads and extracts ZIP files in a single streaming pass — no temporary files, no download-then-extract.
- True streaming extraction — parses local file headers sequentially, extracts files as bytes arrive over HTTP
- Store and Deflate compression (covers ~99% of ZIP files in the wild)
- CRC32 verification for data integrity
- Zip64 support for large archives
- Path traversal protection — rejects
../and absolute paths - Auto-wrapping — creates a containing folder when the archive has multiple top-level entries
--strip-components— strip leading path components (liketar)- Progress output to stderr with TTY-aware formatting
--json— NDJSON progress output for machine consumption
brew install refo/tap/zipstreamcurl -fsSL https://raw.githubusercontent.com/refo/zipstream/main/install.sh | shOr install to a custom directory:
INSTALL_DIR=~/.local/bin curl -fsSL https://raw.githubusercontent.com/refo/zipstream/main/install.sh | shscoop bucket add refo https://github.com/refo/scoop-bucket
scoop install zipstreamPre-built binaries for all platforms are available on the Releases page.
Requires Zig 0.15.2.
git clone https://github.com/refo/zipstream.git
cd zipstream
zig build -Doptimize=ReleaseFastThe binary will be at zig-out/bin/zipstream.
zipstream <url> [options]
| Flag | Description |
|---|---|
-o, --output <dir> |
Extract to directory (default: .) |
--strip-components <n> |
Strip N leading path components |
--json |
Output progress as NDJSON to stderr |
-h, --help |
Show help |
# Extract a GitHub repo archive
zipstream https://github.com/user/repo/archive/main.zip
# Extract to a specific directory
zipstream https://example.com/data.zip -o /tmp/data
# Strip the top-level directory (common for GitHub archives)
zipstream https://github.com/user/repo/archive/main.zip --strip-components 1 -o ./repoWith --json, progress is emitted as NDJSON (one JSON object per line) to stderr:
{"type":"progress","file":"repo-main/large-file.bin","bytes_downloaded":65536}
{"type":"extract","file":"repo-main/large-file.bin","bytes_downloaded":131072}
{"type":"done","files_extracted":42,"bytes_downloaded":1048576,"output":"/tmp/out"}Event types:
progress— periodic update during file extraction (throttled)extract— file extraction completedwarning— non-fatal issue (unsupported compression, bad filename)error— fatal error withmessagefielddone— extraction finished successfully
When Content-Length is available, progress and extract events include bytes_total and percent fields.
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Usage error |
| 2 | Network/HTTP error |
| 3 | ZIP format error |
| 4 | I/O error |
ZIP files store a central directory at the end of the archive, but each file entry also has a local file header immediately before its data. zipstream exploits this by parsing local headers sequentially from a forward-only HTTP stream:
[LFH₁][data₁] [LFH₂][data₂] ... [Central Dir] [End Record]
↑ read ↑ read ↑ stop
When a non-local-header signature is encountered (central directory), extraction stops. This means the entire archive never needs to exist on disk.
- Encrypted ZIPs are rejected
- Compression methods other than Store (0) and Deflate (8) are skipped with a warning
- Multi-disk archives are not supported
MIT