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
| Setting | Type | Range | Notes |
|---|---|---|---|
| Operation | choice | remember, forget, clear, count | Required |
| Memory | string | 1–100 chars | Required. The store's name |
| Scope | choice | run, session, persist, shared | Where it lives |
| Key | string | ≤ 500 chars | Required for forget. Often {{variable}}-bound |
| Value | string | ≤ 2000 chars | A simple value to store |
| Fields | list | ≤ 20 entries | Structured value: named fields Memory Match can reference |
| TTL seconds | integer | 1–31536000 (1 year) | How long the entry lives |
| Count variable | identifier | ≤ 100 chars | Where count writes its result |
The four scopes
| Scope | Survives run end | Survives restart | Shared across instances |
|---|---|---|---|
run | No | No | No |
session | Yes | No — one app launch | No — private per instance |
persist | Yes | Yes | No — private per instance |
shared | Yes | Yes | Yes |
shared is genuinely sharedEvery 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:
| Field | Value |
|---|---|
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
| Port | Taken when | Required |
|---|---|---|
| Success | The operation completed | Yes |
| Fatal | Invalid configuration | No — 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
persistby default for cooldown guards — it survives restarts and stays per-device. - Reserve
sharedfor 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
runscope is in-memory and effectively free.session,persistandsharedare SQLite-backed. Fast, but real I/O — avoid arememberinside a very tight inner loop.countscans the memory's live entries; with large memories, maintain your own counter variable instead.clearis a bulk operation — cheap, but it destroys everything under that name in that scope.
Memory notes
runscope lives on the execution context and is released when the run finalizes.sessionis 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.persistandsharedrows carry an absolute expiry, so expired entries are reclaimed rather than accumulating.- Entries with a one-year TTL in
persistreally do stay for a year. Choose deliberately.
Common mistakes
| Mistake | What happens | Fix |
|---|---|---|
| Scope mismatch with Memory Match | Never matches | Use identical name and scope |
Using shared for per-device state | Instances overwrite each other | Use persist |
Expecting session to survive a restart | Empty after relaunch | Use persist |
forget with no key | Configuration error | forget requires a key |
| Storing one concatenated string | Cannot match with tolerance | Use structured fields |
| No TTL | Entries live until cleared | Always 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.
Related nodes
- Memory Match — the reader
- Variable — single values for this run
- Read Text — usually supplies the identity to remember
Related pages
- Variables and Memory — scopes explained in full