Skip to main content

Runtime Memory

Remembers, forgets, clears, or counts entries in a key/value store with a per-entry lifetime.

Where a Variable answers "what is true right now in this run", Runtime Memory answers "have I already dealt with this thing, and how recently?"

Purpose

Store multiple entries under a named memory, each with its own TTL, in a scope you choose — from run-local to shared across every instance.

When to use it

  • Cooldown guards: "don't touch this target again for 15 minutes".
  • Recording what has already been processed this session.
  • Coordinating a claimed-item list across instances.
  • Counting how many things you have handled.

When not to use it

  • For a single value in this run — use a Variable.
  • For a device fact that never expires — use a per-instance variable.
  • To pass arguments to a Sub Flow — use its input mapping.

Requirements

A memory name and an operation. forget additionally requires a key.

How it runs

The node performs one operation against the named memory in the chosen scope. Every operation routes a single Success — the ports are static, not operation-driven.

Entries expire by absolute time, so an entry written with a 900-second TTL is still expired after an app restart. Nothing has to clean it up.

Settings

SettingTypeRangeNotes
Operationchoiceremember, forget, clear, countRequired
Memorystring1–100 charsRequired. The store's name
Scopechoicerun, session, persist, sharedWhere it lives
Keystring≤ 500 charsRequired for forget. Often {{variable}}-bound
Valuestring≤ 2000 charsA simple value to store
Fieldslist≤ 20 entriesStructured value: named fields Memory Match can reference
TTL secondsinteger1–31536000 (1 year)How long the entry lives
Count variableidentifier≤ 100 charsWhere count writes its result

The four scopes

ScopeSurvives run endSurvives restartShared across instances
runNoNoNo
sessionYesNo — one app launchNo — private per instance
persistYesYesNo — private per instance
sharedYesYesYes
shared is genuinely shared

Every other scope namespaces entries per instance, so instance A can never read or overwrite instance B's memory. shared is the single deliberate opt-in for cross-instance coordination — and ten instances writing the same key will overwrite each other. For anything per-device, use persist.

Structured fields

Rather than one opaque value, store named fields:

FieldValue
x_coordinate{{current_x}}
y_coordinate{{current_y}}

Memory Match can then reference each one as {{item.x_coordinate}}, which is what makes tolerance matching possible.

Blank keys auto-generate

A remember with no key generates a unique one. Use this when entries are a list (things you have handled) rather than a map (facts about specific keys).

Ports

PortTaken whenRequired
SuccessThe operation completedYes
FatalInvalid configurationNo — never followed

Every operation routes Success. There is no Failure port.

Basic example

Count what is stored:

  • Operation: count
  • Memory: processed_targets
  • Scope: run
  • Count variable: processed_count

Realistic example — the cooldown guard

The canonical pattern, and the reason this node exists:

Because the entry carries a 900-second TTL, the guard expires by itself after 15 minutes. There is no cleanup step, no reset flow, and no risk of a stale list growing forever.

Advanced example — session-scoped work log

Track what this app launch has already completed, without it surviving a restart:

  • Operation: remember
  • Memory: completed_today
  • Scope: session
  • Key: {{account_name}}
  • TTL: 86400

A fresh launch starts clean; within one launch, every flow on that instance sees the same log.

Best practices

  • Prefer TTL over manual cleanup. An entry that expires itself cannot leak.
  • Use persist by default for cooldown guards — it survives restarts and stays per-device.
  • Reserve shared for genuine cross-instance coordination.
  • Store structured fields, not concatenated strings. Matching on fields is far more robust.
  • Match the TTL to the real cooldown. Too short and you re-process; too long and you skip work you should do.
  • Use the same memory name and scope on both the Runtime Memory and Memory Match nodes — a mismatch is the top cause of "Memory Match never matches".

Performance notes

  • run scope is in-memory and effectively free.
  • session, persist and shared are SQLite-backed. Fast, but real I/O — avoid a remember inside a very tight inner loop.
  • count scans the memory's live entries; with large memories, maintain your own counter variable instead.
  • clear is a bulk operation — cheap, but it destroys everything under that name in that scope.

Memory notes

  • run scope lives on the execution context and is released when the run finalizes.
  • session is backed by the shared database under a per-launch token; the app reclaims previous launches' rows at startup, so it does not grow without bound.
  • persist and shared rows carry an absolute expiry, so expired entries are reclaimed rather than accumulating.
  • Entries with a one-year TTL in persist really do stay for a year. Choose deliberately.

Common mistakes

MistakeWhat happensFix
Scope mismatch with Memory MatchNever matchesUse identical name and scope
Using shared for per-device stateInstances overwrite each otherUse persist
Expecting session to survive a restartEmpty after relaunchUse persist
forget with no keyConfiguration errorforget requires a key
Storing one concatenated stringCannot match with toleranceUse structured fields
No TTLEntries live until clearedAlways set one

Troubleshooting

Memory Match never matches what I remembered. Check that both nodes use the same memory name and the same scope, and that the field names in the match expression match the fields you stored.

Entries vanish after restarting the app. That is session scope. Use persist.

Two instances are skipping each other's work. They share a shared-scope memory. Switch to persist.

The count is higher than expected. Expired entries are reclaimed lazily; count reports live entries, so verify your TTLs.

FAQ

What is the maximum TTL? One year (31,536,000 seconds).

Do entries expire while the app is closed? Yes — expiry is absolute time, not a countdown.

Can one flow write and another read? Yes, within the same scope and instance (or any instance for shared).

How many fields can an entry have? Up to 20.