Groovy

Get and Set Dynamic Process Property (DPP) and Dynamic Document Property (DDP) in Boomi Groovy Scripts

  • Chirag Kumar DeoChirag Kumar Deo
  • 05 Oct 2026
Get and set Dynamic Process Property (DPP) and Dynamic Document Property (DDP) in Boomi Groovy

This guide shows how to get and set a Dynamic Process Property (DPP) and a Dynamic Document Property (DDP) in a Boomi Groovy script, with copy-paste code for ExecutionUtil.getDynamicProcessProperty, setDynamicProcessProperty and document.dynamic.userdefined.

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.

If you have ever seen a process where every record ended up with the last record’s ID, or a property that was set in one shape and mysteriously empty in the next, this is almost certainly why. Once the difference between process-level and document-level values is clear, a whole class of Boomi problems simply disappears — and scripts become much easier to write. In almost every integration I build, these two kinds of property carry the essential context: the run’s start time, the file a record came from, the ID the target system assigned, the URL to call next.

DPP vs DDP: what is the difference?

A DPP holds one value for the whole process execution; a DDP holds a separate value on every document.

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.

An analogy that sticks

Think of a process execution as a delivery van and documents as the parcels in it. A DPP is written on the van’s dashboard: today’s route number, the time the van left the depot, how many parcels were delivered so far. A DDP is the label on each parcel: who it is for, where it came from, its tracking number. If you write a parcel’s address on the dashboard, every parcel goes to the same house.

Where else these properties come from

You don’t need a script to use them. The Set Properties shape can set both kinds from constants, document data, connector properties (such as the incoming file name) or other properties, and most shapes can read them — in maps, decisions, connector parameters and, as covered in Make HTTP calls in Boomi, as replacement variables in URLs and headers. Scripts are simply the most flexible way to calculate them. Everything in this guide works alongside values set with shapes, as long as the names match exactly.

Kind of propertySet byLives forTypical use
Process property (component)defined in a component, overridden per environmentconfigurationsettings that change per environment
Dynamic process property (DPP)Set Properties or scriptone execution (optionally persisted)run ID, last-run date, counters
Dynamic document property (DDP)Set Properties or scriptone documentfile name, record ID, routing key
Connector document propertiesconnectors (e.g. SFTP file name, HTTP headers)one documentmetadata about where a document came from

The Boomi 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.

Two consequences of this structure trip people up. First, the script sees every document at once, so a DPP set inside the loop is overwritten on each iteration — fine for counters, wrong for per-document values. Second, not storing a document removes it, which is how you filter documents in a script, and also how documents vanish by accident when an exception is caught and the storeStream call is skipped.

How to get and set a Dynamic Process Property (DPP) in Groovy

Get a DPP with ExecutionUtil.getDynamicProcessProperty() and set it with ExecutionUtil.setDynamicProcessProperty():

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.

Persisting a DPP between runs

The third argument to setDynamicProcessProperty decides whether the value survives after the execution ends. With true, the next execution of the same deployed process starts with the stored value. This is the mechanism behind the most useful pattern in integration work — the incremental sync:

import com.boomi.execution.ExecutionUtil

// At the start of the run: where did we get to last time?
String since = ExecutionUtil.getDynamicProcessProperty("DPP_LAST_RUN") ?: "2026-01-01T00:00:00"

// Remember when THIS run started (store it at the end, only on success)
String runStart = new Date().format("yyyy-MM-dd'T'HH:mm:ss", TimeZone.getTimeZone("UTC"))
ExecutionUtil.setDynamicProcessProperty("DPP_RUN_START", runStart, false)

A query then uses DPP_LAST_RUN as its filter (records modified since then), and a final step — reached only when everything succeeded — copies DPP_RUN_START into DPP_LAST_RUN with persistence on. If the run fails half way, the stored value is unchanged and the next run retries the same window. The same idea is described from the connector side in Connect Salesforce with Boomi and NetSuite REST with SuiteQL.

Note: Persisted values belong to the deployed process in a specific environment. They are visible (and can be edited) in runtime management, which is handy for re-syncing: move the date back and the next run picks up older records.

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)

Counters like this are useful for run summaries: a final step can report “120 bills read, 117 created, 3 rejected” — far more useful to the business than a green tick.

How to get and set a Dynamic Document Property (DDP) in Groovy

DDPs live in each document’s props. Get one with props.getProperty() and set it with props.setProperty(), using 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.

Naming conventions

Pick a convention and use it everywhere: DDP_ and DPP_ prefixes, upper case, words separated by underscores (DDP_ORDER_NO, DPP_LAST_RUN). It makes properties instantly recognisable in maps and connector settings, and avoids the case-sensitivity typos that cause most “empty property” bugs.

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.

The same works for JSON with JsonSlurper — see Working with JSON in Groovy — and the pattern is identical: read the text once, extract what you need, set the DDP, store a fresh stream.

Example: carry the file name onto every record

When one file is split into many records, each record should still know which file it came from. Copy the original properties into each new document and add the record-level values:

import java.util.Properties

for (int i = 0; i < dataContext.getDataCount(); i++) {
    Properties fileProps = dataContext.getProperties(i)
    String fileName = fileProps.getProperty("document.dynamic.userdefined.DDP_FILE_NAME")
    int lineNo = 0

    dataContext.getStream(i).getText("UTF-8").eachLine { line ->
        if (lineNo++ == 0 || !line.trim()) return      // skip header and blank lines
        Properties p = new Properties()
        p.putAll(fileProps)
        p.setProperty("document.dynamic.userdefined.DDP_LINE_NO", lineNo.toString())
        dataContext.storeStream(new ByteArrayInputStream(line.getBytes("UTF-8")), p)
    }
}

Now an error report can say “line 14 of bills_0611.csv failed”, which is exactly what the business needs — the approach used in file-driven integrations like Truck Accessory Bill Payment Automation.

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.

Log what the script decided, not the data itself: counts, IDs, which branch was taken. Payloads can contain personal or financial data that shouldn’t sit in logs, and huge log lines make Process Reporting slow to use.

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).
  • Persisting a “last run” value at the start of the run, so a failed run skips records next time.
  • Expecting a DDP set on one document to appear on documents created later from a different source (for example a connector response) — copy it across explicitly if you need it.

Test scripts on your machine

Editing scripts inside a Data Process shape and re-running test mode is slow. With a small harness that imitates dataContext and ExecutionUtil, you can run these exact scripts locally against sample files and see every output document with its DDPs and DPPs printed — see Set up VS Code to run and test Boomi Groovy scripts locally.

Frequently asked questions

How do I get a dynamic process property in a Boomi Groovy script?

Call ExecutionUtil.getDynamicProcessProperty("NAME"). It returns the value as a String, or null if it has not been set.

How do I set a dynamic document property in Groovy?

Call props.setProperty("document.dynamic.userdefined.NAME", value) on the document’s properties, then pass props to dataContext.storeStream().

Why is my DDP empty in the next shape?

Usually the property was set after storeStream, the name has a typo (names are case-sensitive), or the document.dynamic.userdefined. prefix is missing.

How do I keep a value between process runs?

Set a DPP with the third argument true: ExecutionUtil.setDynamicProcessProperty("NAME", value, true). The next execution of the same deployed process reads it back with getDynamicProcessProperty.

Can I read a DDP that was set with a Set Properties shape?

Yes. A DDP named DDP_FILE_NAME in Set Properties is document.dynamic.userdefined.DDP_FILE_NAME in a script — same property, two ways of addressing it.

Further reading

Need a hand?

Properties are small, but they hold most of an integration’s logic together. If you are untangling a process where values leak between documents, or designing incremental syncs that must never miss a record, the Boomi integration consultant page explains how I can help — or get in touch directly.