Study guide

7.4 Object Store: Persisting Data Between Flow Executions

Salesforce Certified MuleSoft Developer I Exam

Track your progress as you read

Finished sections get a check mark.

1 Chapter 1: Creating Application Networks & API-Led Connectivity

1.1 The IT Delivery Gap & API-Led Connectivity Architecture 1.2 Application Network Foundations & Center for Enablement (C4E) 1.3 Anypoint Platform Architecture & Core Components

2 Chapter 2: Designing APIs with RAML & API Designer

2.1 RAML 1.0 Fundamentals, Data Types & Resource Hierarchy 2.2 Reusable API Fragments, ResourceTypes & Traits 2.3 API Mocking Service, Documentation & Anypoint Exchange Publishing

3 Chapter 3: Accessing and Modifying Mule Events

3.1 Mule 4 Event Architecture: Message, Payload, Attributes & Variables 3.2 Flow Variable Management & Target Variables Pattern 3.3 Accessing Event Metadata, Inbound Attributes & Context Properties

4 Chapter 4: Structuring Mule Applications

4.1 Modular Flow Composition: Flows, Subflows & Private Flows 4.2 Configuration Property Files & Environment Management 4.3 Secure Properties Tool, Encryption & Maven Project Packaging

5 Chapter 5: Building API Implementation Interfaces

5.1 APIkit Scaffolding, Router Configuration & Interface Generation 5.2 HTTP Listener Configuration, Path Matching & Query/URI Parameters 5.3 Interface vs. Implementation Separation & Backend Flow Wiring

6 Chapter 6: Using Connectors & External Systems

6.1 Database Connector: Select, Insert, Update, Stored Procedures & Watermarking 6.2 HTTP Request Connector: Headers, Query Params, Response Timeouts & Target Variables 6.3 Salesforce Connector, JMS Messaging & File/FTP Connectors

7 Chapter 7: Processing Records & Batch Integration

7.1 For Each Scope: Payload Iteration, Batch Size & Streaming Data 7.2 Batch Job Architecture: Input, Process, and Complete Phases 7.3 Batch Step Accept Expression, Failure Handling & Batch Aggregator 7.4 Object Store: Persisting Data Between Flow Executions

8 Chapter 8: Transforming Data with DataWeave 2.0

8.1 DataWeave 2.0 Syntax, Type System & Selectors 8.2 Core Functions: map, filter, pluck, reduce, groupBy & orderBy 8.3 Custom Functions, Format Transformations & Type Coercion 8.4 Calling Mule Flows from DataWeave & Reusing DataWeave Modules

9 Chapter 9: Routing Events & Flow Control

9.1 Choice Router: Conditional Expressions & Default Routing 9.2 Scatter-Gather Router: Parallel Execution, Aggregation & Error Traps 9.3 Async Scope, Round Robin & First Successful Routing 9.4 Validating Mule Events with the Validation Module

10 Chapter 10: Handling Errors & Exception Management

10.1 Mule 4 Error Object Hierarchy & Custom Error Types 10.2 On-Error Continue vs. On-Error Propagate Mechanisms 10.3 Try Scope Exception Isolation & Global Error Handling Strategies

11 Chapter 11: Debugging and Troubleshooting Mule Applications

11.1 Logger Configuration, Categories & Thread/Context Diagnostics 11.2 Anypoint Studio Debugger: Breakpoints, Expression Watches & Step-Through 11.3 MUnit 2.x Testing: Unit Tests, Mocking Connectors & Assertions

12 Chapter 12: Deploying and Managing APIs and Integrations

12.1 CloudHub 1.0 & 2.0 Architecture: Workers, vCores & Clustering 12.2 Runtime Manager: Application Management, Alerts, Insights & Logs 12.3 API Manager: Auto-Discovery, API Gateway, SLA Tiers & Standard Policies

7.4 Object Store: Persisting Data Between Flow Executions

Key Takeaways Explain This Topic AI

Every Mule 4 application gets an implicit default object store that is persistent and requires no configuration; you only declare os:object-store when you need custom TTL, capacity, or in-memory behavior.

The core operations are os:store , os:retrieve , os:contains , os:remove , os:retrieve-all-keys , os:retrieve-all , and os:clear , all in the os: namespace.

Retrieving a missing key raises OS:KEY_NOT_FOUND unless you supply a os:default-value child element; storing over an existing key with failIfPresent="true" raises OS:KEY_ALREADY_EXISTS.

entryTtl, maxEntries, and expirationInterval must be configured together — supplying only one is a configuration error, and expiration only happens when the sweeper runs.

On CloudHub, worker disks are ephemeral, so a persistent object store is backed by Object Store v2: values up to 10 MB, keys up to 1024 bytes, and a maximum TTL of 30 days.

Last updated: August 2026

Object Store: Persisting Data Between Flow Executions

A Mule event lives and dies inside a single flow execution. Its payload , attributes , and variables are discarded the moment the flow completes, so nothing a flow computes is visible to the next execution of that same flow. Yet many integration patterns depend on exactly that kind of memory: remembering the last synchronized timestamp, caching an OAuth token until it expires, deduplicating a message ID that a broker redelivered, or counting attempts before giving up. The Salesforce Certified MuleSoft Developer I blueprint calls this out as its own objective — apply correct processors/syntax to persist data between flow executions — and the component that satisfies it is the Object Store .

1. Why Variables Are Not Enough +-----------------------------------------------------------------------------------------+

  • | VARIABLE LIFETIME vs. OBJECT STORE LIFETIME |
  • | |
  • | EXECUTION 1 (10:00:00) EXECUTION 2 (10:05:00) |
  • | +--------------------------+ +--------------------------+ |
  • | | vars.lastId = 4021 | | vars.lastId = (undefined)| <-- vars did NOT carry |
  • | | os:store 'lastId' = 4021 | | os:retrieve 'lastId' | over |
  • | +--------------------------+ | --> 4021 | <-- object store DID |
  • | | +--------------------------+ |
  • | v ^ |
  • | [ OBJECT STORE: { "lastId": 4021 } ] -------+ |
  • | (survives flow end; survives restart when persistent="true") |
  • +-----------------------------------------------------------------------------------------+

An exam question that describes a scheduled flow that must not reprocess records it already handled , or an HTTP token that should be reused until it expires , is asking for an Object Store. Distractors typically offer a flow variable (destroyed at flow end), a Set Payload (destroyed just as fast), or writing to the worker's local disk (destroyed when a CloudHub worker restarts).

2. The Implicit Default Store

Every Mule application ships with a default object store that is persistent and available without any configuration . If you drop an <os:store> operation into a flow and never declare a store, that default store is what you get. <flow name="record-last-sync-flow">

  • <scheduler doc:name="Every 5 Minutes">
  • <scheduling-strategy>
  • <fixed-frequency frequency="5" timeUnit="MINUTES"/>
  • </scheduling-strategy>
  • </scheduler>
  • <!-- Read the watermark saved by the PREVIOUS execution -->
  • <os:retrieve key="lastSyncTimestamp" target="lastSync" doc:name="Retrieve Watermark">
  • <os:default-value><![CDATA[#[|1970-01-01T00:00:00Z|]]]></os:default-value>
  • </os:retrieve>
  • <db:select config-ref="Database_Config" doc:name="Select Changed Rows">
  • <db:sql>SELECT * FROM orders WHERE updated_at > :since</db:sql>
  • <db:input-parameters><![CDATA[#[{'since': vars.lastSync}]]]></db:input-parameters>
  • </db:select>
  • <!-- Write the new watermark for the NEXT execution -->
  • <os:store key="lastSyncTimestamp" doc:name="Store Watermark">
  • <os:value><![CDATA[#[now()]]]></os:value>
  • </os:store>
  • </flow>

Two details in that snippet are heavily tested. First, <os:retrieve> writes the retrieved value into the payload by default; the target attribute is what redirects it into vars.lastSync and leaves the payload untouched. Second, without the <os:default-value> child, the very first execution — when the key does not exist yet — fails with OS:KEY_NOT_FOUND .

3. Declaring a Custom Object Store

When you need a bounded cache, an expiry policy, or an explicitly in-memory store, declare one globally with <os:object-store> and point operations at it with the objectStore attribute. <os:object-store name="tokenCache"

  • persistent="false"
  • maxEntries="500"
  • entryTtl="30"
  • entryTtlUnit="MINUTES"
  • expirationInterval="1"
  • expirationIntervalUnit="MINUTES"
  • doc:name="Token Cache"/>
  • <flow name="get-oauth-token-flow">
  • <os:contains key="crmAccessToken" objectStore="tokenCache" target="hasToken" doc:name="Token Cached?"/>
  • <choice doc:name="Cached or Fetch">
  • <when expression="#[vars.hasToken]">
  • <os:retrieve key="crmAccessToken" objectStore="tokenCache" doc:name="Reuse Token"/>
  • </when>
  • <otherwise>
  • <http:request method="POST" config-ref="Auth_Config" path="/oauth/token" doc:name="Fetch New Token"/>
  • <os:store key="crmAccessToken" objectStore="tokenCache" doc:name="Cache Token">
  • <os:value><![CDATA[#[payload.access_token]]]></os:value>
  • </os:store>
  • <set-payload value="#[payload.access_token]" doc:name="Token Only"/>
  • </otherwise>
  • </choice>
  • </flow>
  • Configuration Attributes

Attribute Meaning Exam-relevant behavior

persistent true survives a runtime restart; false keeps entries in memory only The implicit default store is persistent ; an in-memory store is emptied by every restart or redeploy

maxEntries Maximum number of keys retained When the ceiling is reached the store evicts the oldest entries

entryTtl / entryTtlUnit How long an entry stays valid An entry past its TTL is eligible for removal, not instantly removed

expirationInterval / expirationIntervalUnit How often the expiration sweeper runs An entry with a 30-minute TTL and a 1-hour sweep can survive up to ~90 minutes

Warning

The Three Attributes Travel Together entryTtl , maxEntries , and expirationInterval are mutually dependent: configure all three or none of them . Declaring only entryTtl is a configuration error, and it is a favourite distractor in "which XML is valid?" questions.

4. The Operation Set

Operation XML element Payload / effect Error when it goes wrong

Store <os:store key="…"> Writes a value; overwrites by default OS:KEY_ALREADY_EXISTS when failIfPresent="true" ; OS:NULL_VALUE on a null value

Retrieve <os:retrieve key="…"> Returns the stored value as the new payload OS:KEY_NOT_FOUND if the key is absent and no <os:default-value> is set

  • Contains <os:contains key="…"> Returns a Boolean OS:INVALID_KEY on a null/blank key
  • Remove <os:remove key="…"> Deletes one entry OS:KEY_NOT_FOUND if the key is absent
  • Retrieve All Keys <os:retrieve-all-keys/> Returns an Array of key strings OS:STORE_NOT_AVAILABLE
  • Retrieve All <os:retrieve-all/> Returns the whole store as an Object OS:STORE_NOT_AVAILABLE
  • Clear <os:clear/> Empties the store OS:STORE_NOT_AVAILABLE
  • Idempotent Consumption Pattern

The classic combination — used to discard a JMS or HTTP message the application has already seen — pairs contains with store : <flow name="idempotent-order-intake">

<jms:listener config-ref="JMS_Config" destination="orders" doc:name="On Order"/>

<os:contains key="#[payload.orderId]" target="alreadySeen" doc:name="Seen Before?"/>

  • <choice doc:name="Duplicate Check">
  • <when expression="#[vars.alreadySeen]">
  • <logger level="WARN" message="#['Discarding duplicate order ' ++ payload.orderId]" doc:name="Log Duplicate"/>
  • </when>
  • <otherwise>
  • <os:store key="#[payload.orderId]" doc:name="Mark Processed">
  • <os:value><![CDATA[#[now()]]]></os:value>
  • </os:store>
  • <flow-ref name="processOrderFlow" doc:name="Process Order"/>
  • </otherwise>
  • </choice>
  • </flow>

Note where the key comes from: a DataWeave expression on the message , not a literal. Keys are strings, and expressions that resolve to a number must be coerced ( #[payload.orderId as String] ) when the source system supplies numeric IDs.

5. Object Store v2 on CloudHub

CloudHub worker disks are ephemeral, so "persistent" on CloudHub does not mean "written to the worker's file system". A persistent store on CloudHub is backed by Object Store v2 (OSv2) , a shared cloud service that is also what lets multiple workers of the same application see the same keys .

  • OSv2 constraint Published limit
  • Maximum key length 1024 bytes (UTF-8)
  • Maximum value size 10 MB (Base64-encoded)
  • Maximum TTL 2,592,000 seconds (30 days)
  • Number of keys per application No documented limit

Important

Multi-Worker State Lives in OSv2, Not in Memory If an exam scenario deploys an application across two or more CloudHub workers and asks how a counter, token, or watermark stays consistent, the answer is a persistent object store backed by Object Store v2 . An in-memory store ( persistent="false" ) gives each worker its own private copy, so the two workers disagree — a classic wrong-answer trap dressed up as "faster".

Tip

Object Store vs. Batch vs. Cache Scope The Cache scope also uses an object store underneath, but it caches a computed result keyed by an expression . When the question describes remembering a value across separate flow executions , choose the Object Store connector. When it describes avoiding recomputation of an expensive downstream call within the same request pattern, the Cache scope is the better fit.