How to folder → zip in developer workflows
- Step 1Decide if Folder → ZIP is even the right tool — Interactive, one-off, want everything in the folder? Use Folder → ZIP. Need to exclude
node_modules/.git, or want only*.ts? Use selective-zipper. Need a specific level or smallest size? Use smart-archive-compressor. Need it in CI? Usezip/tarin the pipeline. - Step 2Prune before you pack (Folder → ZIP has no filter) — Because it packs everything the browser exposes, delete or move
node_modules,.git,distcaches, and editor junk out of the folder first if you don't want them in the ZIP — or switch to the glob-based selective-zipper. - Step 3Pick the folder via the picker — Click the dropzone (Pick or drop a folder to ZIP) and select the folder. The
webkitdirectorypicker walks subfolders; drag-drop often grabs only top-level files, so prefer the click path — verify the Files count matches what you expect. - Step 4Run and read the metrics —
fflate.zipSyncpacks at level 6. The result shows Files, Folder (the download name), and Saved. A near-zero Saved on adist/full of minified+gzipped assets is expected; the ZIP is bundling, not re-compressing. - Step 5Normalise timestamps for reproducible artifacts — If you compare artifact hashes across builds, run the ZIP through timestamp-normalizer (default epoch 1980-01-01) so identical content hashes identically — the browser equivalent of
zip -Xplus fixed dates. - Step 6For automation, use the runner or a CLI — There's no server API for archive tools. On paid tiers, pair the @jadapps/runner so jobs run locally outside the tab. For unattended CI packing, add a
zip/tarstep to your pipeline instead — Folder → ZIP is an interactive tool, not a build primitive.
Dev task → right tool
Folder → ZIP's deliberate gaps mapped to the JAD sibling or CLI that fills them. Use it where its simplicity helps and reach elsewhere when you need a real feature.
| Dev task | Use | Why not Folder → ZIP |
|---|---|---|
| Bundle a minimal repro for a bug report | Folder → ZIP | It's the right tool — quick, local, full tree |
| ZIP only source, excluding node_modules/.git | selective-zipper | Folder → ZIP has no exclude filter; packs everything |
| Smallest possible artifact | smart-archive-compressor (level 9) | Folder → ZIP is fixed at level 6 |
| Reproducible / hashable artifact | timestamp-normalizer | Folder → ZIP writes real mtimes, so hashes vary |
| ZIP a folder inside CI | zip/tar in the pipeline | No server API; archive tools are browser-only |
| Encrypt the artifact | encrypted-zip-creator | Folder → ZIP output is plaintext |
| Inspect an artifact's entries | archive-previewer | Folder → ZIP creates, it doesn't read |
Fixed behaviours that matter to devs
The tool's empty option schema means these are not tunable. Knowing them avoids surprises in code review and artifact comparison.
| Behaviour | Value | Implication for devs |
|---|---|---|
| Compression level | Deflate 6 (fixed) | Artifacts a few % larger than zip -9; identical method |
| Exclude/include filter | None | node_modules/.git/dist get packed; prune or use selective-zipper |
| Timestamps | File lastModified per entry | Non-reproducible by default; normalise for stable hashes |
| Output format | ZIP only | No tar.gz/7z; convert afterward if needed |
| Output filename | <top-folder>.zip | Name your folder deliberately; no rename field |
| Automation surface | Local runner only | Not a CI primitive; use zip/tar in pipelines |
Cookbook
Dev-shaped recipes, with the CLI equivalent shown so you can map a terminal habit to the browser flow.
Minimal repro case for a bug report
The ideal Folder → ZIP job: small, self-contained, and you want the whole thing.
Folder: repro/ repro/index.html repro/main.js repro/styles.css repro/steps.md Folder → ZIP -> repro.zip (Files: 4, Saved: 58%) Attach repro.zip to the issue. Reviewer unzips the exact tree, opens index.html, reproduces. CLI equivalent: zip -r repro.zip repro/
Source-only bundle (skip node_modules)
Folder → ZIP would include node_modules. Use the glob sibling to scope to sources.
Don't: Folder → ZIP on the whole project
-> 30,000-entry ZIP, mostly node_modules
(also blows past free/Pro entry caps)
Do: selective-zipper, pattern: src/**/*
-> src.zip with only your code
CLI equivalent: zip -r src.zip src/ -x '*/node_modules/*'Reproducible artifact for hash comparison
Default ZIPs embed real mtimes, so two builds differ. Normalise to compare.
build A -> dist.zip -> sha256 = aaaa... build B -> dist.zip -> sha256 = bbbb... (mtimes differ) Folder → ZIP -> timestamp-normalizer (epoch 1980-01-01) build A -> sha256 = zzzz... build B -> sha256 = zzzz... (identical if content same) Now 'did the build change?' is a hash diff.
Smallest artifact for a size-sensitive upload
Folder → ZIP is level 6. For a marketplace/extension upload with a hard size cap, squeeze harder.
Folder → ZIP (level 6): ext.zip 812 KB smart-archive-compressor (level 9): ext.zip 761 KB On minified JS the gap is small; on raw text it's larger. CLI equivalent: zip -9 -r ext.zip ext/
Snapshot a config tree before a risky change
Quick local safety net before editing infra/config files — bundle, then proceed.
Folder: ./config-2026-06-13/ (copy of live config) Folder → ZIP -> config-2026-06-13.zip If the change goes wrong, unzip to restore. For encrypted off-machine storage of secrets-bearing config, re-pack with encrypted-zip-creator instead.
Edge cases and what actually happens
Trying to call a Folder → ZIP API from CI
No APIThere is no public server endpoint for archive tools — they run only in the browser (or the local runner). A CI job can't POST a folder to be zipped by JAD. Use zip/tar in the pipeline. The runner path is for accelerating interactive use on your own machine, not for headless CI.
node_modules / .git ended up in the artifact
No filterFolder → ZIP packs everything the browser exposes — there's no exclude option. Either prune the folder first, or use selective-zipper with a glob to include only the files you want (e.g. src/**/*). A full-project ZIP also tends to blow past the entry caps.
Whole-repo ZIP exceeds the entry-count cap
Tier limitA repo with node_modules easily exceeds 50,000 entries (Pro) let alone 500 (free). Scope to source with selective-zipper, or upgrade — Pro-media/Developer allow 500,000 entries. The byte size is often fine; it's the entry count that bites.
Artifact hash changes every build
ExpectedFolder → ZIP writes each file's real lastModified, so rebuilds produce different bytes even with identical content — same as a default zip. Run timestamp-normalizer (epoch 1980-01-01) to get reproducible, comparable artifacts.
Expecting executable bits / symlinks to survive
Not carriedThe browser File API doesn't expose POSIX modes or symlinks, so a script's +x bit and any links are lost. For artifacts where permissions matter (e.g. a release tarball), build it with tar -czf on the source machine, not from the browser.
Drag-drop missed the subfolders
Use the pickerDropping a folder reads dataTransfer.files, which usually doesn't recurse — you get only top-level files. Click the dropzone to use the webkitdirectory picker, which walks the whole tree. Check the Files count if the artifact looks thin.
Wanting a smaller artifact than level 6 gives
Use a siblingFolder → ZIP can't change the level. Use smart-archive-compressor at level 9, or the zip -9 CLI. On already-minified/gzipped assets even level 9 barely helps — that's a property of the data, not the tool.
Large dist/ makes the tab hang briefly
Memory boundzipSync builds the archive in memory in one pass, so a large dist/ momentarily spikes RAM and can freeze the tab — it completes. For incremental in-browser packing, streaming-zip-builder uses fflate's streaming Zip class instead.
Frequently asked questions
Is there an API to automate Folder → ZIP?
No public server API — archive tools are browser-only. The only automation hook is the local @jadapps/runner on paid tiers, which runs the job on your machine outside the tab. For headless CI packing, add a zip or tar step to your pipeline; Folder → ZIP is an interactive tool, not a build primitive.
Can I exclude node_modules or .git?
Not in Folder → ZIP — it has no exclude filter and packs everything the browser exposes. Either prune the folder first, or use selective-zipper with a glob (e.g. src/**/*) to include only the files you want. A whole-repo ZIP also tends to exceed the entry-count caps.
Can I set the compression level?
No — it's fixed at Deflate level 6. For level control (0 store, up to 9 max) use smart-archive-compressor, or zip -9 on the CLI. On minified/gzipped assets, higher levels barely help; on raw source they save a few percent.
How do I get reproducible artifacts?
Folder → ZIP embeds real file timestamps, so artifacts differ build-to-build. Run the ZIP through timestamp-normalizer (default epoch 1980-01-01) to make identical content hash identically — the JAD equivalent of zip -X plus fixed dates.
Does it preserve my directory structure?
Yes — relative paths from webkitRelativePath become ZIP entry paths, so src/components/Button.tsx round-trips exactly. Whoever unzips the artifact sees the same tree you had locally.
Will it keep executable bits and symlinks?
No. The browser File API doesn't expose POSIX modes or symlinks, so they're not stored. For release tarballs where permissions matter, build with tar -czf on the source machine instead of zipping from the browser.
Can it output tar.gz or 7z for a Unix target?
No — ZIP only. Convert afterward with zip-to-tar-gz, but note that neither path recovers Unix permissions (they were never read). If the target needs permissions and symlinks, use tar on the host.
What's the runner and how does it help devs?
On paid tiers, JAD can dispatch a job to a local @jadapps/runner you've paired — it runs the same tool on your machine, outside the browser tab, which helps with larger inputs. It is still entirely local (no JAD server), and it's for interactive acceleration, not headless CI.
Why is my dist.zip barely smaller than the folder?
Because dist/ is usually minified JS/CSS and already-compressed images — Deflate can't shrink entropy-coded data, so the Saved figure approaches zero. The ZIP still bundles everything into one artifact, which is the point here.
How do I ZIP only TypeScript (or one file type)?
Use selective-zipper with a glob like src/**/*.ts or **/*.{ts,tsx}. Folder → ZIP can't filter — it packs the whole folder. The selective tool is the include-side equivalent of zip -x excludes.
Can I inspect an artifact's contents in the browser?
Yes — Folder → ZIP only creates archives, but archive-previewer lists every entry without extracting, and file-listing-generator exports the listing as CSV/JSON/TXT for tooling.
Why did drag-dropping my project miss most files?
Drag-drop reads dataTransfer.files, which usually doesn't recurse into subfolders, so you get only top-level files. Click the dropzone to use the webkitdirectory picker, which traverses the whole tree. Verify the Files count after picking.
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.