Groovy

Dynamic Process and Document Properties in Boomi Groovy Scripts

  • Chirag Kumar DeoChirag Kumar Deo
  • 05 Oct 2026
Groovy code reading a dynamic process property and setting a dynamic document property

Boomi gives you two kinds of “variables” you will use constantly, and mixing them up is one of the most common sources of confusing bugs.

One process-level value shared by all documents, and one document-level value per document.
One process-level value shared by all documents, and one document-level value per document.
Dynamic Process Property (DPP)Dynamic Document Property (DDP)
Scopethe whole process executionone document
Typical userun ID, last-run date, counters, config flagsfile name, record ID, target URL, routing key
Persist between runsoptionalno

Rule of thumb: if the value is the same for every document, use a DPP. If every document can have its own value, use a DDP.

The Groovy script skeleton

Scripts run in a Data Process shape with the Custom Scripting step. A script receives all documents and must write each one back out, otherwise it disappears from the process:

import java.util.Properties
import java.io.InputStream
import com.boomi.execution.ExecutionUtil

for (int i = 0; i < dataContext.getDataCount(); i++) {
    InputStream is = dataContext.getStream(i)
    Properties props = dataContext.getProperties(i)

    // ... your logic ...

    dataContext.storeStream(is, props)
}
Data Process shape with a Custom Scripting step in Groovy (illustration).
Data Process shape with a Custom Scripting step in Groovy (illustration).

props holds that document’s properties, including its dynamic document properties.

Dynamic process properties

Read and write them with ExecutionUtil:

import com.boomi.execution.ExecutionUtil

// read (null if not set)
String lastRun = ExecutionUtil.getDynamicProcessProperty("DPP_LAST_RUN")

// write: the third argument controls persistence between executions
ExecutionUtil.setDynamicProcessProperty("DPP_LAST_RUN", new Date().format("yyyy-MM-dd'T'HH:mm:ss"), true)

Values are always stored as text, so convert numbers yourself, and remember that names are case-sensitive.

Example: count documents across the whole run

import com.boomi.execution.ExecutionUtil

int count = (ExecutionUtil.getDynamicProcessProperty("DPP_COUNT") ?: "0") as int

for (int i = 0; i < dataContext.getDataCount(); i++) {
    count++
    dataContext.storeStream(dataContext.getStream(i), dataContext.getProperties(i))
}

ExecutionUtil.setDynamicProcessProperty("DPP_COUNT", count.toString(), false)

Dynamic document properties

DDPs live in each document’s props, with the prefix document.dynamic.userdefined.:

// read: same name you used in Set Properties
String fileName = props.getProperty("document.dynamic.userdefined.DDP_FILE_NAME")

// write: visible to later shapes as DDP_FILE_NAME
props.setProperty("document.dynamic.userdefined.DDP_FILE_NAME", "orders_" + i + ".csv")

Watch out: Set the property before storeStream. Changes made after the document has been stored are not carried forward.

Example: take a value from the document into a DDP

Read an order number from each XML document and store it as a DDP so a later HTTP call or file name can use it:

import java.util.Properties
import java.io.InputStream

for (int i = 0; i < dataContext.getDataCount(); i++) {
    InputStream is = dataContext.getStream(i)
    Properties props = dataContext.getProperties(i)

    String text = is.getText("UTF-8")
    def order = new XmlSlurper().parseText(text)
    props.setProperty("document.dynamic.userdefined.DDP_ORDER_NO", order.OrderNumber.text())

    // the stream was consumed, so store a fresh one
    dataContext.storeStream(new ByteArrayInputStream(text.getBytes("UTF-8")), props)
}

Reading a stream consumes it; always store a new stream built from the text, as above.

Log what you are doing

def logger = ExecutionUtil.getBaseLogger()
logger.info("Processing " + dataContext.getDataCount() + " documents")

Log lines appear in the process log in test mode and in Process Reporting.

Common mistakes

  • Using a DPP for per-document values: the last document overwrites the value for everyone.
  • Forgetting storeStream, which silently drops documents.
  • Reading is.getText() and then storing the same (now empty) stream.
  • A name typo (they are case-sensitive).

Further reading