How to empty folder pruner vs command-line zip cleanup
- Step 1Decide by format — If the archive is a ZIP, the browser tool works directly. For 7z/rar/tar.gz the CLI (7z, bsdtar) wins because the pruner is ZIP-only.
- Step 2Decide by size — Under ~500 MB the browser tool is fine on Pro. Multi-GB archives, or in-place edits to avoid a full rewrite, favour a CLI like
zip -d. - Step 3Decide by repeatability — A scripted CLI step in CI beats clicking a page for recurring jobs. For ad-hoc cleanup the page is faster than writing a script.
- Step 4Match the delete logic —
zip -d archive.zip '*/'deletes ALL directory records (even useful ones, which most readers recreate); the JAD tool deletes only UNreferenced ones, keeping directories that contain files. - Step 5Account for timestamps — The browser tool resets entry dates on rebuild;
zip -dpreserves the remaining entries' dates. If you need stable dates either way, normalise afterward. - Step 6Verify the result — List the output (
unzip -lor the tool's metrics panel) and confirm the empty directory records are gone and every file remains.
Browser pruner vs common CLI approaches
Behaviour comparison for removing empty directory entries from a ZIP. The JAD column reflects pruneEmptyFolders in lib/archive/archive-processor.ts.
| Aspect | JAD Empty Folder Pruner | `zip -d archive '*/'` | Python `zipfile` script |
|---|---|---|---|
| Install needed | None (browser page) | Info-ZIP installed | Python installed |
| Delete logic | Only directories with no files under them | ALL directory records (you craft the glob) | Whatever you code |
| Mutates input | No — emits <name>-pruned.zip | Yes — in place | Your choice |
| Formats | ZIP only | ZIP only | ZIP via zipfile |
| Size ceiling | 50 MB free / 2 GB paid (in RAM) | Disk-bound | Disk-bound |
| Entry timestamps | Reset to processing time | Preserved for kept entries | Whatever you code |
| Uploads data | Never | Never (local) | Never (local) |
Tier limits that apply to the Empty Folder Pruner
Limits are enforced per input file before pruning begins (lib/tier-limits.ts, archive family). The pruner reads ONE ZIP at a time on every tier — it is not a batch tool, so the batch-files column only matters for sibling tools that accept folders. entryLimit counts every entry in the ZIP central directory, including the empty directory records you are trying to remove.
| Tier | Max ZIP size | Max entries per ZIP | Files per run |
|---|---|---|---|
| Free | 50 MB | 500 entries | 1 |
| Pro | 500 MB | 50,000 entries | 20 (other tools) |
| Pro + Media | 2 GB | 500,000 entries | 100 (other tools) |
| Developer | 2 GB | 500,000 entries | unlimited (other tools) |
| Enterprise | unlimited | unlimited | unlimited |
Cookbook
Equivalent CLI commands next to the browser tool's behaviour, so you can pick the path that fits. Output listings are illustrative.
The careful CLI equivalent
The closest CLI to the JAD logic must avoid deleting directories that hold files. A blanket zip -d archive '*/' over-deletes; you'd need to enumerate empties yourself. The browser tool computes this for you.
# Over-deletes ALL dir records (readers recreate them on extract): zip -d release.zip '*/' # JAD equivalent (deletes ONLY empty dir records, keeps files' parents): # drop release.zip into /archive-tools/empty-folder-pruner -> release-pruned.zip
Python: list empty directory records
To match the JAD logic in Python you derive referenced directories from file names, then rewrite without the unreferenced directory entries — exactly what the tool does internally.
import zipfile, posixpath
zin = zipfile.ZipFile('release.zip')
files = [n for n in zin.namelist() if not n.endswith('/')]
refdirs = set()
for f in files:
p = posixpath.dirname(f)
while p:
refdirs.add(p + '/'); p = posixpath.dirname(p)
keep = [i for i in zin.infolist() if not i.filename.endswith('/') or i.filename in refdirs]
# rewrite 'keep' into release-pruned.zip ...Inspect before you prune
List directory records first so you know what will go. The browser tool shows the same result as an 'Empty dirs removed' count after processing.
# CLI: show only directory records
unzip -l release.zip | awk '$4 ~ /\/$/ {print $4}'
logs/
tmp/
src/ <- has files, will be KEPT by JAD
# JAD: result panel reports 'Empty dirs removed = 2'Reproducible build pairing
Neither path gives stable timestamps automatically (the browser tool resets them; zip -d preserves originals). For deterministic ZIPs, normalise after pruning.
# CLI: zip -d release.zip '*/empty-only-dirs*' strip-nondeterminism release.zip # or set SOURCE_DATE_EPOCH at build # JAD: prune -> Timestamp Normaliser (/archive-tools/timestamp-normalizer) -> stable dates
Non-ZIP archive
The browser pruner is ZIP-only. For tar.gz or 7z, a CLI is the right tool, or convert to ZIP first then prune.
# tar.gz has no real empty-dir bloat problem the same way, but to clean a 7z: 7z d archive.7z -r '*/' -x'!*.* ' # CLI handles 7z; JAD does not # Or convert then prune in-browser: # archive.7z -> Archive Format Converter -> archive.zip -> Empty Folder Pruner
Edge cases and what actually happens
`zip -d '*/'` deleted folders you needed
Over-deletionA blanket glob removes every directory record, including ones that hold files (most readers recreate them, but it changes the listing). The JAD tool avoids this by keeping any directory referenced by a file.
Archive is 7z/rar/tar.gz
Use CLIThe browser tool reads ZIP only and rejects other formats with 'Not a valid ZIP archive.' Use 7z/bsdtar, or convert to ZIP first with Archive Format Converter.
Multi-GB archive
Use CLIThe browser tool holds the whole archive in memory and is capped at 2 GB on paid tiers. For larger ZIPs, a streaming CLI or in-place zip -d is the better fit.
You expected timestamps preserved
DiffersUnlike zip -d, which keeps remaining entries' dates, the JAD tool rebuilds the ZIP and resets every date to the processing time. Use Timestamp Normaliser if dates matter.
Encrypted ZIP
Not supportedfflate's unzipSync cannot read encrypted entries, so the browser tool fails on password-protected ZIPs. A CLI with the password, or decrypt-then-prune, is required.
In-place edit required
Use CLIThe browser tool always emits a new <name>-pruned.zip; it never mutates the original. If your workflow needs in-place editing, zip -d does that directly.
Recurring CI job
Use CLIFor a step that runs on every build, a scripted CLI command is more appropriate than a manual browser action. The browser tool shines for one-off, ad-hoc cleanups.
Untrusted archive on a locked-down machine
Use browserOn a machine where you cannot install Info-ZIP or Python, the browser tool needs nothing but a tab — and never uploads the file, so untrusted input stays local.
You only want to SEE what's empty
By designThe browser tool has no preview-only mode; it prunes and reports the count. To inspect first, list directory records with unzip -l or use File Listing Generator before pruning.
Frequently asked questions
Is the browser tool's output identical to the CLI's?
Structurally the kept entries match, but the JAD output is a freshly rebuilt ZIP with reset timestamps and fflate level-6 compression, whereas zip -d edits in place and keeps remaining entries' dates and original compression.
Which deletes the 'right' folders?
The JAD tool deletes only directory records that no file references, so it never drops a folder that contains files. A blanket zip -d '*/' deletes all directory records — usually fine, but it changes the listing more aggressively.
When is the CLI clearly better?
Multi-GB archives, non-ZIP formats (7z/rar/tar.gz), in-place edits, encrypted archives, and recurring CI steps. The browser tool is RAM-bound and ZIP-only.
When is the browser tool clearly better?
Ad-hoc cleanups, machines where you can't install tools, untrusted input you don't want on disk, and anyone who'd rather not write a glob or script.
Does either path upload my data?
No. The JAD tool runs entirely in your browser tab; a local CLI runs on your machine. Both keep the archive on-device.
Can the browser tool match Python's flexibility?
No — it has no options and one fixed behaviour. If you need custom rules (keep certain empties, rename, filter), a Python zipfile script is the way.
Why does the browser output reset timestamps?
It rebuilds the ZIP with fflate, which writes the current time to entries when no mtime is supplied. Run Timestamp Normaliser afterward for stable dates.
Does `zip -d '*/'` remove files too?
No, the '*/' glob targets directory entries (names ending in '/'), not files. But it removes ALL such records, including directories that contain files, which the JAD tool would keep.
Can I batch many ZIPs in the browser?
Not with this tool — it processes one ZIP per run on every tier. For many archives, scripting a CLI loop is the practical route.
Is there a size where the browser tool fails?
Yes: over your tier cap (50 MB free, 500 MB Pro, 2 GB Pro+Media/Developer) or over the entry limit (500/50,000/500,000). Beyond that, use a CLI.
Do I need the same delete logic in both?
Only if you care about keeping directories that hold files. zip -d '*/' is blunter; the JAD tool and the Python snippet in the cookbook both preserve referenced directories.
What about tar.gz empty folders?
tar stores explicit directory members too, but the browser tool can't read tar.gz. Use bsdtar/tar to filter, or convert to ZIP first with Archive Format Converter.
Privacy first
Every JAD Archive tool runs entirely in your browser using fflate, @zip.js/zip.js, and the libarchive WASM bridge. Your archives never leave your device — verified by zero outbound network requests during processing.