Get, set, delete
Importkv from twenty-sdk/logic-function. Values can be any JSON-serializable payload.
src/logic-functions/sync-linear-issues.ts
Scopes
Each entry has a scope, passed as an option on every call. The default isWORKSPACE.
WORKSPACE(default) — the entry is private to the current workspace install of your app. Each workspace that installs the app gets its own independent set of keys. This is what you want for caches, cursors, and per-workspace state.SERVER— the entry is shared across every install of your app on the server. Server entries behave like claims: the stored value is always the workspaceId that claimed the key (omitvalueonsetto claim the key for the current workspace), and only that workspace can overwrite or delete it. Any install can read the entry.
kv.set throws when the key is already claimed by another workspace.
Use it: cache an expensive call
A typical use is caching a slow or rate-limited third-party response so repeated runs reuse it instead of paying the cost every time.src/logic-functions/getExchangeRate.logic-function.ts
Patterns & tips
- Namespacing. Prefix keys to keep different concerns apart —
sync-cursor:linear,cache:exchange-rate:USD:EUR,lock:nightly-report. - Expiry (TTL). The store has no built-in expiration. Store a timestamp inside the value (as in the cache example) and check it on read, or clear stale keys from a cron-triggered function.
- What to store. Any JSON-serializable value — numbers, strings, arrays, objects. Keep entries small; this is for coordination and caching, not large blobs or files. For files, use a
FILESfield anduploadFile. - Visibility. Entries live in the instance database, not as workspace records — they never show up in the workspace UI, aren’t part of your app’s data model, and need no role or object permissions.
Alternative: a queryable store object
The built-in store is deliberately opaque: entries aren’t records, so you can’t browse them in the UI, relate them to other objects, or filter them with record queries. When you need any of that — say a visible sync log, or per-record state — define a small technical object with a uniquekey field and a RAW_JSON value field instead, and query it through the typed API client. See Objects for the defineObject reference and Data → Unique indexes for enforcing key uniqueness.
- Scoping to a record. Add a relation from the store object to the target object rather than encoding the id into the key.
- Visibility & permissions. Rows live in the workspace database like any other record, so they’re queryable through the API and respect your app’s role. To keep the store out of the main UI, leave it off your navigation menu.
Unlike the built-in store, a custom object is always scoped to one workspace — it can’t share entries across installs the way
SERVER keys do.