Durable State

services.state stores small versioned values owned by a workflow across runs and process restarts.

Example use case

A daily report workflow can remember the last successfully processed record ID. Tomorrow's run reads that cursor, processes only newer records, then updates it after success.

JavaScript
const cursor = await services.state.get("last-record");
return { cursor: cursor.found ? cursor.value : 0 };

State is authoritative and durable; cache is not. Keep values small and JSON-compatible. Use a database for collections, queries, and application records.

Build a cross-run counter

JavaScript
const updated = await services.state.increment(
  "successful-order-count",
  1,
  { name: "increment-successful-order-count" }
);

return {
  count: updated.value,
  version: updated.version
};

Every mutation requires a stable operation name. If a retried step repeats the same logical mutation, WOML reattaches to the original committed result rather than incrementing twice.

Use compare-and-set

Read a value and version, then pass ifVersion to a mutation when concurrent runs must not overwrite one another blindly. A version conflict tells the workflow to reload and make a deliberate decision.

Choose state instead of cache

Use state when a workflow must remember a small cursor, watermark, feature setting, one-winner initialization, or permanent counter across future runs and restarts. Use cache only when a miss is harmless.

State does not automatically enter context; every read is an explicit managed operation. It does not expire or evict. Do not store secrets, large collections, or queryable application records in it. Protect the state database and backups because state values are not transparently encrypted.