Skip to main content

Variables and secrets

When writing scripts, you may want to reuse variables, or safely pass secrets to scripts. You can do that with Variables. Windmill has user-defined variables and contextual variables.

Variables are dynamic values that have a key associated to them and can be retrieved during the execution of a Script or Flow.

All Variables (not just secrets) are encrypted with a workspace specific symmetric key to avoid leakage.

There are two types of Variables in Windmill: user-defined and contextual.

User-defined variables

User-defined Variables is essentially a key-value store where every user can read, set and share values at given keys as long as they have the privilege to do so.

They are editable in the UI and also readable if they are not Secret Variables.

Inside the Scripts, one would use the Windmill client to interact with the user-defined Variables.

import wmill

wmill.get_variable("u/user/foo")
wmill.set_variable("u/user/foo", value)

Note that there is a similar API for getting and setting Resources which are simply Variables that can contain any JSON values, not just a string and that are labeled with a Resource Type to be automatically discriminated in the auto-generated form to be of the proper type (e.g. a parameter in TypeScript of type pg: Postgresql is only going to offer a selection over the resources of type postgresql in the auto-generated UI).

There is also a concept of state to share values across script executions.

Contextual variables

Contextual Variables are environment variables automatically set by Windmill. This is how the Deno and Python clients get their implicit credentials to interact with the platform.

See the Contextual tab on the Variable page for the list of reserved variables and what they are used for.

You can use them in a Script by clicking on "+Context Var":

Contextual variable

NameExample of valueDescription
WM_WORKSPACEdemoWorkspace id of the current script
WM_TOKENq1E2qcLyO00yxioll7oph76N9CJDqnToken ephemeral to the current script with equal permission to the \ permission of the run (Usable as a bearer token)"
WM_EMAIL[email protected]Email of the user that executed the current script
WM_USERNAMErubenUsername of the user that executed the current script
WM_BASE_URLhttps://app.windmill.dev/base url of this instance
WM_JOB_ID017e0ad5-f499-73b6-5488-92a61c5196ddJob id of the current script
WM_JOB_PATHu/user/script_pathPath of the script or flow being run if any
WM_FLOW_JOB_ID017e0ad5-f499-73b6-5488-92a61c5196ddJob id of the encapsulating flow if the job is a flow step
WM_ROOT_FLOW_JOB_ID017e0ad5-f499-73b6-5488-92a61c5196ddJob id of the root flow if the job is a flow step
WM_FLOW_PATHu/user/flow_pathPath of the encapsulating flow if the job is a flow step
WM_SCHEDULE_PATHu/user/triggering_flow_pathPath of the schedule if the job of the step or encapsulating step has \ been triggered by a schedule"
WM_PERMISSIONED_ASu/henriFully Qualified (u/g) owner name of executor of the job
WM_STATE_PATHu/user/flow_path/c_henriState resource path unique to a script and its trigger
WM_STATE_PATH_NEWu/user/flow_path/c_henriState resource path unique to a script and its trigger (legacy)
WM_FLOW_STEP_IDcThe node id in a flow (like 'a', 'b', or 'f')
WM_OBJECT_PATHu_user_flow_path/u_user_flow_path/c/17[...]196ddScript or flow step execution unique path, useful for storing results in an external service
WM_OIDC_JWTeyJh[...]ciOiJIUzI1NiIsInR5OIDC JWT token (EE only)

Custom contextual variables

From Variables tab, admins can create custom contextual variables that will act as env variables for all jobs within a workspace.

We still recommend using user-defined variables but in some cases (e.g. your imports depend on env variables), this might be a good escape hatch.

Create Custom Contextual Variable

Secrets

Secrets are encrypted when stored on Windmill. From a usage standpoint, secrets are kept safe in three different ways:

  • Secrets can only be accessed by users with the right permissions, as defined by their path. In addition, secrets can be explicitly shared with users or groups. A secret in u/alice/secret will only be accessible by alice, unless explicitly shared. A secret in f/devops/secret will be accessible by anyone with read access to f/devops.
  • Secrets cannot be viewed outside of scripts. Note that a user could still print a secret if they have access to it from a script.
  • Accessing secrets generates variables.decrypt_secret event that ends up in the Audit logs. It means that you can audit who accesses secrets. Additionally you can audit results, logs and script code for every script run.

Add a variable or secret

You can define variables from the Variables page. Like all objects in Windmill, variable ownership is defined by the path - see ownership path prefix.

Variables also have a name, generated from the path, and names are used to access variables from scripts.

A variable can be made secret. In this case, its value will not be visible outside of a script.

Add variable

Accessing a variable from a script

Accessing contextual variables from a script

See the Contextual tab on the Variable page for the list of reserved variables and what they are used for.

You can use them in a Script by clicking on "+Context Var":

Contextual variable

Reserved variables are passed to the job as environment variables. For example, the ephemeral token is passed as WM_TOKEN.

Accessing user-defined variables from a script

There are 2 main ways variables are used within scripts:

Passing variables as parameters to scripts

Variables can be passed as parameters of the script, using the UI-based variable picker. Underneath, the variable is passed as a string of the form: $var:<variable_path> and replaced by the worker at time of execution of the script by fetching the value with the job's permissions. So the job will fail if the job's permissions inherited from the caller do not allow access to the variable. This is the same mechanism used for resource, but they use $res: instead of $var:.

Select Variable

Fetching them from within a script by using the wmill client in the respective language

By clicking on + Variable, you'll get to pick a variable from your workspace and be able to fetch it from within the script.

Fetch Variable

TypeScript:

wmill.getVariable('u/user/foo');

Python:

wmill.get_variable("u/user/foo")

Go:

wmill.GetVariable("u/user/foo")

Bash:

curl -s -H "Authorization: Bearer $WM_TOKEN" \
"$BASE_INTERNAL_URL/api/w/$WM_WORKSPACE/variables/get/u/user/foo" \
| jq -r .value

PowerShell:

$Headers = @{
"Authorization" = "Bearer $Env:WM_TOKEN"
}
Invoke-RestMethod -Headers $Headers -Uri "$Env:BASE_INTERNAL_URL/api/w/$Env:WM_WORKSPACE/variables/get/u/user/foo"

The last examples in bash and PowerShell showcase well how it works under the hood: It fetches the secret from the API using the job's permissions through the ephemeral token passed as an environment variable to the job.

Custom environment variables

In a self-hosted environment, Windmill allows you to set custom environment variables for your scripts. This feature is useful when a script needs an environment variable prior to the main function executing itself. For instance, some libraries in Go do some setup in the 'init' function that depends on environment variables.

To add a custom environment variable to a script in Windmill, you should follow this format: <KEY>=<VALUE>. Where <KEY> is the name of the environment variable and <VALUE> is the corresponding value of the environment variable.

Environment variables passed to jobs

From a worker group, you can add static and dynamic environment variables that will be passed to jobs handled by this worker group. Dynamic environment variable values will be loaded from the worker host environment variables while static environment variables will be set directly from their values below.