Bundle files into ZIP
The "Bundle files into ZIP" service task combines multiple file references – for example from previous service tasks, upload activities or form fields – into a single ZIP archive and returns a new file reference to the resulting archive. This is ideal for offering several generated documents as one download or for archiving all artefacts of a process in a single bundle.
This service is the counterpart of “Unzip ZIP file”: its output (files and groups) can be passed in unchanged as input here. Round-trip scenarios such as “unzip → process individual files → zip again” work out of the box.
When to use this service task
- Bulk download of generated documents: Multiple generated PDFs (e.g. all invoices of a month) are combined into a single archive offered for download.
- Archival: At the end of a process, all resulting receipts, logs and exports are bundled into one ZIP for long-term storage.
- Export with folder structure: A data export contains several categories (invoices, bookings, receipts) that are represented as separate folders inside the archive.
- Round-trip with "Unzip ZIP file": An incoming archive is extracted, individual files are transformed, and the result is zipped again – without having to rebuild the original folder structure manually.
Input parameters
The task accepts the following fields:
{
"files": [
{
"referenceId": "...",
"filename": "invoice-001.pdf",
"contentType": "application/pdf"
}
],
"groups": {
"invoices": [
{
"referenceId": "...",
"filename": "invoice-002.pdf",
"contentType": "application/pdf"
}
]
},
"output_filename": "archive.zip",
"compressionLevel": 5,
"maxFiles": 5000,
"maxTotalBytes": 2147483648
}
Explanation:
files: List of file references placed directly at the root of the ZIP archive (optional). Each entry containsreferenceId,filenameandcontentType.groups: Object whose keys represent folder paths inside the ZIP. The associated list contains file references that will be stored asfoldername/filename(optional).output_filename: Name of the generated archive (optional, default:"archive.zip"). The.zipextension is enforced automatically.compressionLevel: Compression level between0and9(optional, default:5).0– no compression, fastest processing, largest file.5– balanced (default).9– maximum compression, slowest processing, smallest file.
maxFiles: Maximum number of files that may be added to the archive (optional, default:5000).maxTotalBytes: Maximum total uncompressed size in bytes (optional, default:2147483648= 2 GB).
At least one source required
Either files or groups (or both) must contain at least one entry. Without input files the task aborts with an error.
Output
The task returns a single file reference to the generated ZIP archive:
{
"referenceId": "...",
"filename": "archive.zip",
"contentType": "application/zip"
}
Explanation:
referenceId: Reference to the generated file in the data lake. It can be passed on to downstream tasks, for example to send the archive via email, upload it to SharePoint/FTP, or attach it to a data object.filename: The actual filename used (always with.zipextension).contentType: Alwaysapplication/zip.
JSONata examples
Simple case – all files flat in the archive:
{
"files": $.allPdfs,
"output_filename": "invoices_2026.zip"
}
With folder structure:
{
"groups": {
"invoices": $.invoiceFiles,
"bookings": $.bookingFiles
},
"output_filename": "export.zip"
}
Round-trip – repack the result of "Unzip ZIP file":
{
"files": $.unzipResult.files,
"groups": $.unzipResult.groups,
"output_filename": "repacked.zip"
}
Maximum compression for small archives:
{
"files": $.documents,
"compressionLevel": 9,
"output_filename": "small.zip"
}
Notes
- Round-trip compatible: The input structure exactly mirrors the output of “Unzip ZIP file”. Extra fields from the unzip output such as
countorskippedare simply ignored. - Streaming processing: Files are read one by one from the data lake and written directly into the archive. Memory usage stays bounded even with many or large files.
- Name collisions: If multiple files end up on the same path inside the archive (e.g. two
invoice.pdfin the same group), a counter is appended automatically:invoice.pdf,invoice_2.pdf,invoice_3.pdf. - Path sanitizing: Leading slashes and path-traversal patterns (
..) are stripped from filenames before the entry is written. - Extension enforced: If
output_filenameis provided without a.zipextension, it is added automatically. compressionLevel = 0: Files are only bundled, not compressed. Useful for archives containing already compressed formats (PDF, JPG, PNG) where additional compression offers little benefit but costs time.
Limits and why they exist
The parameters maxFiles and maxTotalBytes act as safeguards against accidentally oversized archives:
- Memory and runtime protection: Very large ZIPs can exceed the service task's maximum runtime or overwhelm downstream systems (email attachments, uploads).
- Protection against configuration mistakes: JSONata expressions that unintentionally resolve to a huge list of file references are caught early.
maxTotalBytesapplies to the uncompressed total size derived from the metadata of the source files. The limit therefore still kicks in even if compression would reduce the final size drastically.
The default values (5000 files, 2 GB) are generous and should rarely need to be changed for typical bulk exports. For particularly large archives the limits can be raised explicitly – keeping in mind the technical constraints of the following steps.
Tip
In combination with “Unzip ZIP file” a complete processing loop can be modelled: an incoming archive is unzipped, each file is transformed or validated inside a multi-instance subprocess, and the result is packed into a new ZIP with the same folder structure. Because both services share the exact same schema, it is enough to pass files and groups straight through.