Unzip
Actionarrow.up.bin
action.unzip
Extract a .zip archive to real files on disk, then send those files downstream. The archive path comes from the upstream payload (typically {{filePath}} from an Input or Directory Changed trigger). A zip of 200 files is just a document of 200 pages — Unzip fans out over the contents so each file flows through the rest of your workflow on its own.
Two outlets, one extraction
A single extraction feeds both outlets — wire whichever fits whether you want one result for the whole archive or one result per file. (Same pattern as Extract Text (PDF)’s Document/Page split.)
Emits once with the whole archive — the destination directory, a files array of every extracted path, and fileCount. Use it for one action about the whole extraction (e.g. “notify me it’s done”).
Fans out — runs everything downstream once per extracted file, each run carrying that file’s filePath, fileName, and index. Use it to route each file by type — image → OCR/vision, text → AI, and so on.
Ports
Configuration
| Field | Type | Default | Description |
|---|---|---|---|
| archivePath | Variable picker | {{filePath}} | The .zip to extract. Pick the upstream variable that holds the path (a bare key, a {{key}} template, or a literal path all work); blank falls back to filePath. |
| destination | Text | {{directory}}/{{fileName}} | Where to extract. Defaults to a sibling folder next to the archive — this keeps the output out of a watched directory so it doesn’t re-trigger the workflow. |
| overwrite | Dropdown | overwrite | On a name collision at the destination: Overwrite, Keep both (suffix), or Skip existing. |
Output Variables
Merged onto the incoming payload (so upstream keys are preserved). Which keys you get depends on the outlet you wired.
| Variable | Outlet | Description |
|---|---|---|
| destination | Contents | Absolute path to the extraction directory. |
| files | Contents | Array of file refs for every extracted file. |
| fileCount | Contents | Number of files extracted. |
| filePath | File | This file’s absolute path (drops straight into OCR, PDF, AI, Move…). |
| fileName | File | This file’s name. |
| index | File | This file’s 0-based position in the archive. |
| success | Both | true on success; false on a graceful failure (see below). |
Error handling
Two tiers, by design. Everyday problems fail gracefully so a workflow can branch on them; only genuine safety violations hard-fail.
success: falseReturns a normal payload with success: false and an error reason — never throws, so the run continues and a Condition can route the failure.
no_archive_path— no archive path was provided or resolved.archive_not_found— the path is valid but no file exists there.not_a_zip— the file isn’t a readable archive (ditto exits non-zero). This is the “input isn’t an archive” case — it fails gracefully and emits a singlesuccess:falsepayload (not the per-file fan-out).
Throws and marks the node failed (the red banner) only for real safety violations:
protected location— the archive or destination resolves into a denied path (~/Libraryinternals,~/.ssh, system roots) or uses..traversal. iCloud Drive and other cloud folders are allowed.zip-slip / symlink— an entry inside the archive tries to escape the extraction directory or is a symlink. The whole extraction is discarded before anything reaches your destination.
Security
Extraction lands in a private temporary folder first. Every entry is checked to stay inside that folder and symlink entries are rejected, so a malicious archive (zip-slip) is caught and discarded before anything reaches your real destination. Archive and destination paths are validated against the same protected-location rules as Move File; iCloud Drive and other cloud folders are allowed.
Example
Describe every image in a zip: extract, then fan out the File outlet to OCR + an AI vision model.