Skip to content

Data Stores

Data stores provide managed key-value storage for your workflows. Use them to persist data across executions, maintain state between steps, and build lookup tables — all scoped to your organization and accessible from any workflow.

Data is organized into tables, each containing key-value entries. Tables are shared across all workflows in your organization, so any workflow can read or write to any table.

ConceptDescription
TableA named collection of key-value entries (like a database table)
KeyA unique identifier within a table (up to 1,024 characters)
ValueAny JSON-serializable data — strings, numbers, booleans, objects, or arrays

Tables are created automatically when you first write to them using a data store step. You can also create tables from the Data Store page in the sidebar, or from the data store step configuration — the table name dropdown lets you select existing tables or type a new name to create one.

QuickFlo provides five step types for working with data stores. Each step is configured through the visual form builder in the workflow editor.

Retrieve a single value by key.

FieldDescription
TableSelect or type a table name
KeyThe key to look up (supports templates, e.g., user-{{ initial.userId }})

Output available to later steps:

{{ get-user.value }} // the stored value (or null if not found)
{{ get-user.found }} // true or false
{{ get-user.value.email }} // access nested fields from stored objects

Store or update a value. If the key already exists, its value is replaced.

FieldDescription
TableSelect or type a table name
KeyThe key to store under (supports templates)
ValueKey-value pairs defining the data to store
ExpirationOptional TTL — the entry is auto-deleted after this time
OptionDescription
No expirationEntry persists until manually deleted (default)
Custom TTLSet a duration from 1 minute to 1 year

Output:

{{ set-user.success }} // true if stored successfully
{{ set-user.key }} // the key that was written

List all keys in a table with optional prefix filtering.

FieldDescription
TableThe table to list keys from
PrefixOptional — only return keys containing this text
LimitMax results to return (1–1,000, default 100)
OffsetSkip this many results (for pagination)

Output:

{{ list-keys.keys }} // array of key strings
{{ list-keys.total }} // total matching keys
{{ list-keys.hasMore }} // true if more results exist

Search entries by their stored values using field-level filters — like a simple database query.

FieldDescription
TableThe table to query
FiltersOne or more conditions on value fields
Filter ModeAll (every filter must match) or Any (at least one must match)
LimitMax results (1–1,000, default 100)
OffsetSkip results for pagination

Each filter has three parts:

PartDescriptionExample
FieldDot-notation path into the stored valuestatus, user.email, tags
OperatorComparison typeequals, contains, greater than, etc.
ValueThe value to compare againstactive, 100, true

Available operators:

OperatorDescription
equalsExact match
not_equalsNot equal
containsText contains substring
array_containsArray includes a value
gtGreater than
gteGreater than or equal
ltLess than
lteLess than or equal

Output:

{{ query-users.entries }} // array of { key, value } objects
{{ query-users.entries[0].key }} // first result's key
{{ query-users.entries[0].value }} // first result's value
{{ query-users.total }} // total matches
{{ query-users.hasMore }} // true if more results exist

Remove a single entry by key.

FieldDescription
TableThe table to delete from
KeyThe key to delete (supports templates)

Output:

{{ delete-user.deleted }} // true if the key existed and was deleted
{{ delete-user.key }} // the key that was deleted

The Data Store page lets you browse, search, edit, and manage your data store entries directly from the QuickFlo UI.

Data store page showing the tables sidebar and records list

The left sidebar lists all tables in your organization with record counts. Use the search field at the top to filter tables by name. You can also create new tables or refresh the list from the toolbar icons.

Selecting a table shows all its entries in a sortable table with Key, Created, and Updated columns. Each row has edit and delete action buttons. Click any row to open the detail panel.

Detail panel showing record metadata and value tree with syntax highlighting

Clicking a record opens a detail panel showing:

  • Metadata — size, created date, updated date, and expiry countdown (if set)
  • Value preview — the full stored value with syntax highlighting and expandable tree view
  • Clickable values — click any primitive value in the tree to quickly filter by it

From the detail panel you can edit, delete, or copy the key.

The search bar supports two modes:

Key search — type any text to filter entries by key (case-insensitive contains match):

user-123

Value search — use field:value syntax to filter by stored values. Click the Search button or press Enter to execute:

Search bar with a JSONB query filter and active filter badge
SyntaxDescriptionExample
field:valueField contains value (partial match)status:active
field:=valueField equals value (exact match)email:=john@example.com
field:!valueField does not contain valuestatus:!deleted
field:!=valueField does not equal valuestatus:!=inactive
[].field:valueArray element field contains value[].level:123
field[]:valueArray field contains primitive valuetags[]:important

Active filters appear as badges below the search bar that you can dismiss individually.

Edit record dialog showing properties mode with path/value fields and expiration option

Click the edit icon on any record (or from the detail panel) to open the edit dialog. The editor supports two modes:

  • Properties mode — visual path/value pairs with an “Add Property” button
  • JSON mode — raw JSON editor for complex values

You can also toggle Set expiration to add or remove a TTL on the entry.


Table context menu showing Export, Import, and Delete options

Export an entire table as a JSON file from the table toolbar. The export contains an array of key-value objects.

Import data dialog with JSON/CSV tabs and drag-and-drop file upload

Import data from JSON or CSV files into a table. The import dialog supports drag-and-drop file upload and shows a preview of entries before importing. Existing keys are updated (upsert) and new keys are created.


Persist data across workflow executions — for example, tracking which records have been processed to prevent duplicates:

StepConfiguration
GetTable: processed-records, Key: {{ $item.id }}
IfCondition: {{ get-record.found }} equals false
Set (in Then branch)Table: processed-records, Key: {{ $item.id }}, Value: {{ $util.now }}

Store reference data that multiple workflows can use:

StepConfiguration
SetTable: config, Key: region-mapping, Value: JSON with region mappings
Get (in another workflow)Table: config, Key: region-mapping

Access nested values: {{ get-config.value.US }}

Increment a counter across workflow executions:

StepConfiguration
GetTable: metrics, Key: daily-count
SetTable: metrics, Key: daily-count, Value: {{ get-count.value | default: 0 | plus: 1 }}

Use a data store with a TTL to avoid repeating expensive API calls across executions:

  1. Get step: Look up the cache key
  2. If step: Check {{ get-cache.found }}
    • Then branch: Use the cached value
    • Else branch: Call the API, then Set the result with a TTL (e.g., 1 hour)

LimitValue
Key length1,024 characters
Table name length255 characters
Minimum TTL1 minute
Maximum TTLNo expiration (entries persist indefinitely)
Default TTL (when expiration enabled)30 days
Query limit per request1,000 entries
Bulk import per request10,000 entries