Skip to main content
Version: 1.0.8

Variables

Gateway variables are a shared key/value store for a project's pipelines, scripts and screens. They hold the state that does not belong to a tag and does not deserve a database table: a counter, a last-run timestamp, a feature flag, a cached token.

They are the server-side half of the Variables feature. The other half, client variables, lives in one browser tab and never reaches the server. → Context API

Scope New in 1.0.8​

ScopeVisible toDeleted
Project — the defaultThat project's pipelines, Gateway and client scripts, and viewsWith the project
GlobalEvery projectOnly when deleted

A variable belongs to the project that set it unless its name has been declared global. Two projects can each keep a shift_target of their own without colliding. A global name is global everywhere: no project keeps a private copy shadowing it.

To change a variable's scope, use the scope button on its row in the pipeline Variables drawer or the Designer's Gateway variables window. Make global shares it with every project; Make project-scoped asks first, then moves the value into this project, and every other project stops seeing it. A script declares a name global with system.vars.set(name, value, scope="global").

Making a name global is refused while another project still holds its own variable of that name, and the refusal names those projects: promoting it would silently throw their values away. Delete or rename it there first.

Project variables are included when the project is backed up or exported, and purged when it is deleted.

Existing variables became global on upgrade

Variables are keyed by project from 1.0.8. Every persistent variable that existed before the upgrade was moved to global, so every pipeline, script and screen that read it keeps working. Variables created afterwards belong to the project that sets them — so a pipeline in one project no longer sees a new variable another project sets, unless that name is made global. Review the Scope column after upgrading and make project-scoped whatever only one project uses.

Storage modes​

ModeSurvives restartUse for
PersistentYesCounters, last-processed markers, configuration flags
VolatileNoCaches, in-flight state, anything cheap to recompute

The workspace has a default mode; individual variables can override it at write time.

ActionPermission
List variables and read the default modeauthenticated
Change the default storage modeConfigure Shared Variables
Delete a variable, or change its scope 1.0.8Edit Pipeline

Seeing them​

Variables are created and changed by scripts and by the Designer's Set variable action; the interface shows them and lets you delete them or change their scope.

WhereShows
The pipeline workspace's Variables drawerThis project's variables and the global ones: Name, Type, Value, Scope, Where (Persistent or Memory), and the storage default
The Designer's project browser, Variables → GatewayThe same set
The Designer's project browser, Variables → ClientThis project's client variables

Changed in 1.0.8 The pipeline drawer opens at 1100 px — never so wide that less than 120 px of canvas shows — and its left edge drags to resize it, down to 480 px; double-click the edge to reset it. A long value stays on one line, cut off, with the full value as a tooltip; an object or array value expands into a tree, in the drawer and in both Designer windows.

Deleting a variable asks first, naming the variable and what stops working: a project variable's readers in this project, a global variable's readers in every project, or a client variable's bindings. 1.0.8

Using variables​

Python
last = system.vars.get("last_export_ts", 0)
rows = system.db.runQuery(
"SELECT * FROM events WHERE ts > ?", [last], "ReportingDB"
)
if rows:
system.vars.set("last_export_ts", rows[-1]["ts"], "persistent")

count = system.vars.incr("exports_today") # atomic
left = system.vars.decr("labels_left", 10) # atomic subtract

system.vars.set("plant_mode", "RUN", scope="global") # shared by every project
JavaScript
const last = await system.vars.get("last_export_ts", 0);
await system.vars.set("last_export_ts", Date.now(), "persistent");
const count = await system.vars.incr("exports_today");
await system.vars.set("plant_mode", "RUN", undefined, "global");

API​

CallReturns
get(name, defaultValue?)The value, or defaultValue when unset
set(name, value, storage?, scope?)true. storage omitted ⇒ workspace default; scope omitted ⇒ the name keeps its scope
delete(name)true
keys()This project's variable names and the global ones
incr(name, by?)The new value after atomically adding by (default 1)
decr(name, by?) 1.0.8The new value after atomically subtracting by (default 1)
list()This project's variables and the global ones, with value, type, storage, scope and last-updated time

Names are letters, digits and -, _, =, /, ., and may not start or end with a dot. → system.vars

Use incr for counters​

# ❌ race: two pipelines can read the same value and both write n+1
n = system.vars.get("count", 0)
system.vars.set("count", n + 1)

# ✅ atomic
n = system.vars.incr("count")

Variables are shared across concurrently executing pipelines. Read-modify-write loses updates; incr and decr do not.

Patterns​

Incremental extract

last = system.vars.get("etl_watermark", "1970-01-01T00:00:00Z")
rows = system.db.runNamedQuery("changes_since", {"since": last})
# ... process ...
if rows:
system.vars.set("etl_watermark", rows[-1]["updated_at"], "persistent")

Restart-safe: the watermark is persistent, so a restart resumes rather than reprocessing.

Run-once-per-period guard

import datetime
today = datetime.date.today().isoformat()
if system.vars.get("daily_report_date") == today:
return None # already ran
# ... produce the report ...
system.vars.set("daily_report_date", today, "persistent")

Cached credential

token = system.vars.get("api_token")
if not token:
token = fetch_token()
system.vars.set("api_token", token, "volatile") # not written to disk

Variables, tags or a database?​

NeedUse
A process value with quality, history, alarmsA tag (internal tag if QUBIQ owns it)
Coordination state between pipelinesA variable
A setting or a result a screen shows, with no history neededA variable, bound as vars.<name>
A value an operator writes that must be alarmed or kept in historyAn internal tag
Anything queried, reported on or retained long-termA database

A screen can show a gateway variable: bind a property to vars.<name> — read-only, refreshed every few seconds — and write one with the Set variable action, scope Gateway. In a LiveView, operators and anonymous visitors can read only the variables that project's views and client scripts name. 1.0.8 Before 1.0.8 a vars.<name> binding stayed empty for anyone not signed in to the Studio. → Set variable

Cautions​

  • Not encrypted. Do not store credentials you would not want an operator with script access to read. Use a connection's credential storage instead.
  • Not audited per write. Variable changes are not in the security audit journal.
  • One name space per project. Within a project, prefix by concern (etl_watermark, report_lastrun) so unrelated pipelines do not collide — and remember that a global name is shared with every project.
  • Volatile means volatile. A restart clears it, including a supervisor-initiated service restart.

Next​

→ Message bus · REST endpoints