IronFlowDocs

pdf_merge

Merge bounded PDF path or artifact sources sequentially into one atomically published PDF.

Parameters

filesarrayone of files / source_key
Non-empty array of paths, artifact descriptors, or canonical artifact URIs. Path strings support ${ctx.key} interpolation.
source_keystringone of files / source_key
Context key containing the non-empty source array. Useful when prior nodes produced artifact descriptors.
output_pathstringrequired
Merged output path with ${ctx.key} interpolation.
output_keystringdefault "pdf_merge"
Prefix for output values.

files and source_key are mutually exclusive.

Resource and durability contract

Environment variableDefaultBoundary
IRONFLOW_MAX_PDF_MERGE_FILES100Source entries admitted before collection
IRONFLOW_MAX_PDF_BYTES104857600Bytes in each source PDF
IRONFLOW_MAX_PDF_DECOMPRESSED_STREAM_BYTES67108864Decoded bytes per object/cross-reference stream in each source
IRONFLOW_MAX_PDF_OBJECTS250000Loaded objects per source, checked after parsing
IRONFLOW_MAX_PDF_MERGE_BYTES536870912Cumulative input bytes and staged output bytes
IRONFLOW_MAX_PDF_MERGE_PAGES2000Cumulative pages
IRONFLOW_MAX_PDF_MERGE_OBJECTS250000Retained output graph objects

Inputs are opened and parsed one at a time on a tracked blocking worker. For each source, the union of objects reachable from all selected pages is remapped once, so pages sharing fonts, images, or resources do not clone those objects per page. Artifact inputs use the same verified file handle used for identity checking.

Every source passes the shared PDF loading policy, including strict parsing and bounded recovery checks, before graph collection. The loaded object limit includes objects not needed in the merged graph; the retained-output object limit remains separate. Neither is a hard parser memory ceiling.

Before replacing page parents, the node materializes the nearest inherited Resources, MediaBox, CropBox, and Rotate values. Explicit page values take precedence; null values are treated as absent. Inherited indirect resources remain shared and count toward the retained-object limit. Broken or cyclic parent chains fail without replacing an existing output file.

Links between retained pages and annotation backlinks are remapped. Source catalog/page-tree references are disconnected rather than copying the old tree. This is a page-oriented merge, not preservation of document-level outlines, signatures, catalog features, or a general content-redaction operation.

The result is written to a sibling staged file, flushed and synchronized, then atomically committed. Parse, limit, save, and cancellation failures remove the partial staging file and preserve an existing destination. The output refuses a final link or non-regular destination.

Configured parent-directory aliases for output_path, including macOS /tmp, are resolved before staging and missing parent directories are created. Unix pins the resolved directory, so retargeting the alias afterward cannot redirect the write. This is not permission to follow a destination-file symlink.

Artifact inputs require a protected artifact directory visible at the same path on every eligible worker. A shared mount is not an authentication boundary against a process running under the same OS identity.

Context output

  • <output_key>_path — merged PDF path.
  • <output_key>_page_count — total page count.
  • <output_key>_success — true after commit.

Example

local flow = Flow.new("merge_artifacts")

flow:step("sources", function(ctx)
    return { merge_sources = { ctx.first_artifact, ctx.second_artifact } }
end)

flow:step("merge", nodes.pdf_merge({
    source_key = "merge_sources",
    output_path = "/tmp/full-report.pdf"
})):depends_on("sources")

return flow

IronFlow documentation

Find the next step

Type a keyword to search the documentation.

↑ ↓ to move · Enter to open · Esc to close