How to empty folder pruner for build & release engineering
- Step 1Stage the artifact — Pull the release ZIP from your CI artifact store or local
dist/. The tool reads from disk via the File API; nothing transits the network. - Step 2Open the pruner — Go to /archive-tools/empty-folder-pruner. For SDK and desktop bundles over 50 MB, use Pro (500 MB) so you don't have to split.
- Step 3Check entry count — Asset-heavy bundles can exceed the entry limit (500 free, 50,000 Pro). Empty directory records count too, so a folder-heavy artifact may need a higher tier.
- Step 4Prune — Click Process. The tool computes referenced directories from file paths and drops the unreferenced directory records — your files are untouched.
- Step 5Record the count — Note the 'Empty dirs removed' value. Put it in the release log so reviewers can see the artifact was deliberately cleaned.
- Step 6Make it reproducible — If your pipeline targets bit-identical artifacts, send the pruned ZIP through Timestamp Normaliser, then generate a manifest with Checksum Generator.
Where empty directory records come from in release pipelines
Common packaging sources of zero-content directory entries and how the pruner treats them.
| Source | Typical phantom dirs | Pruner result |
|---|---|---|
git archive HEAD | Empty submodule mount points, .github/ if no workflow files selected | Removed if no file lands under them |
| macOS Finder 'Compress' | logs/, tmp/, .cache/ recorded during walk | Removed |
| Gradle/Maven assembly | META-INF/services/ left empty, build/tmp/ | Removed unless a file is present |
npm pack style bundling | Empty node_modules/.bin/, coverage/ | Removed if no file references them |
| Hand-built ZIP with mkdir-then-add | Any folder created before its file was excluded | Removed (no referencing file) |
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
Release-engineering scenarios with before/after listings. Paths reflect typical desktop-app and SDK bundles; the prune decisions match the real logic.
Desktop app bundle with stale cache dirs
A packaging script recorded app/cache/ and app/logs/ before clearing them, so they ship empty and appear in the user's install directory. Pruning removes both; the app's actual folders stay.
Before (MyApp-1.4.0.zip): app/MyApp.exe app/resources/icon.png app/cache/ app/logs/ After (MyApp-1.4.0-pruned.zip): app/MyApp.exe app/resources/icon.png app/resources/ app/ Metrics: Empty dirs removed = 2, Entries = 4
SDK with empty service-loader directory
A Java SDK left META-INF/services/ with no provider files. Strict consumers warn on it. The pruner drops it while keeping every class and resource.
Before (sdk.zip): com/acme/Client.class META-INF/MANIFEST.MF META-INF/services/ After (sdk-pruned.zip): com/acme/Client.class META-INF/MANIFEST.MF Metrics: Empty dirs removed = 1, Entries = 2
Cross-platform extract behaviour
On Windows, empty directory records become real empty folders in the target; on Linux some extractors skip them. Pruning makes extraction consistent across platforms.
Same ZIP, different extractors: Windows Explorer -> creates empty cache\ folder Linux unzip -> may skip empty cache/ macOS Archive Util-> creates empty cache/ After pruning: no extractor creates the phantom folder. Consistent everywhere.
Reproducible release artifact
A reproducible-build target needs identical bytes across machines. Prune, then normalise timestamps to a fixed epoch, then checksum for the release manifest.
Pipeline: 1. Empty Folder Pruner -> release-pruned.zip (phantom dirs gone) 2. Timestamp Normaliser -> fix all dates to 1980-01-01 (ZIP epoch floor) 3. Checksum Generator -> SHA-256 manifest committed alongside the artifact Result: byte-identical release.zip on every build agent.
Pre-release that must not be uploaded
An unsigned nightly shouldn't touch external infrastructure. The browser tool keeps it local end to end — verify in DevTools that no request carries the file.
Reviewer laptop, offline mode: - open /archive-tools/empty-folder-pruner (page cached) - drop nightly-2026.06.13.zip - DevTools Network: 0 requests for the artifact - download nightly-2026.06.13-pruned.zip
Edge cases and what actually happens
Artifact exceeds the size cap
Tier limit exceededFree is 50 MB and Pro 500 MB; large game or media bundles may need Pro+Media (2 GB). The size check runs before pruning, so oversize artifacts fail immediately.
Bundle has tens of thousands of files
Tier limit exceededFree allows 500 entries, Pro 50,000. Asset-dense SDKs can exceed this, and the empty directory records you're removing also count. Upgrade or split with Archive Splitter.
You intentionally ship an empty folder
By designSome installers expect an empty plugins/ or logs/ to exist on first run. The pruner will remove it because no file references it — exclude that artifact from pruning or recreate the folder post-install.
Reproducible build broken by timestamp reset
ExpectedPruning rebuilds the ZIP and resets entry dates, which changes the checksum. Always normalise timestamps after pruning so the manifest stays stable across builds.
Artifact is a 7z or tar.gz
RejectedThe pruner reads ZIP only. Convert with Archive Format Converter first, or handle non-ZIP artifacts with a CLI in your pipeline.
Signed/notarised ZIP
CautionRebuilding the archive invalidates any external signature over the original bytes. Prune BEFORE you sign or notarise, never after.
Encrypted distribution ZIP
Not supportedfflate cannot read encrypted entries, so the pruner fails on password-protected artifacts. Prune the plaintext build, then encrypt with Encrypted ZIP Creator.
Verifying nothing else changed
SupportedTo prove only empty dirs were removed, run Archive Diff between the original and the pruned ZIP — it should report only directory entries removed and (expected) timestamp changes.
Empty-only ZIP (skeleton template)
RemovedA folder-skeleton template with no files will have every directory removed, leaving an empty ZIP. That's correct given the logic — don't prune intentional skeletons.
Frequently asked questions
Is browser-only processing acceptable for pre-release artifacts?
Yes — nothing is uploaded, so the artifact never leaves your machine. This is equivalent to running a local CLI, which most security policies already permit for build tooling.
Will pruning change my shipped files?
No. Only empty directory records are removed; every file entry is preserved byte-for-byte. The structure of folders that contain files is untouched.
Does pruning break reproducible builds?
On its own it can, because the rebuild resets timestamps and changes the checksum. Always follow pruning with Timestamp Normaliser before checksumming.
Can I prune after signing the ZIP?
No — rebuilding invalidates a signature over the original bytes. Prune first, then sign or notarise the cleaned artifact.
What size artifacts can I clean?
Free 50 MB, Pro 500 MB, Pro+Media and Developer 2 GB. Entry limits are 500 / 50,000 / 500,000 respectively, and empty directory records count toward them.
How do I document what was removed?
The result panel shows an 'Empty dirs removed' count and the final entry count. Capture those numbers in your release log; pair with Archive Diff for an entry-level record.
Does it handle 7z or tar.gz release bundles?
No, ZIP only. Convert non-ZIP artifacts with Archive Format Converter, or filter empties with a CLI in the pipeline.
Can multiple engineers use it at once?
Yes — each browser tab is an independent instance with no shared state. Free limits apply per session; Pro removes them.
Is there an API for our CI to call?
Not currently — the tool is a browser page (browser-only by design). For automated CI cleanup, script fflate or zip -d in your pipeline; this tool is for ad-hoc and reviewer cleanup.
Why do empty folders even matter for distribution?
On Windows extractors they materialise as real empty folders in the user's install path, and strict package validators may warn on them. Removing them makes extraction consistent and the bundle cleaner.
Will it remove __MACOSX or .DS_Store from my mac-built ZIP?
No — those are files. Use Filename Sanitiser for macOS cruft, then prune the result if any folders became empty.
Can I confirm only empty dirs changed?
Yes. Run Archive Diff on original vs pruned; expect only removed directory entries plus the (intended) timestamp delta from the rebuild.
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.