Variables overview
A deployment can take configuration from literal YAML or from a variable — for example, a CPU limit, hostname, or API key. Quix offers four kinds of variable, and two routes for getting a value out of one and into your pipeline. This page answers both questions: which kind of variable holds the value, and how that value reaches your quix.yaml or your running container. Each variable kind's own page covers its syntax in full.
Beta feature
Global variables are currently in beta. The other variable kinds on this page are generally available.
Which kind of variable do you need?
| You want to… | Use |
|---|---|
| Share config across multiple projects | Global variables |
Store a per-environment value or secret within one project (CPU, MEMORY, REPLICAS, API keys) |
Project variables |
| Set a static value on one deployment | Environment variables |
| Read a platform-provided identifier | Quix variables |
Environment variables are the basic form of runtime configuration exposed to application code: each is a name/value pair in the deployment's container environment. inputType chooses whether that value is literal, comes from a project variable, or comes from a variable group. See Environment variables for the basics and minimal YAML examples.
Two ways to reference a variable
{{ }} substitution embeds the resolved value directly into a quix.yaml field, as text. Use it for fields that need to vary per environment or across projects but don't need to be secret — resource sizing, public URL prefixes, feature toggles.
{{ VARIABLE_NAME }}— a project variable. See Project variables → Pattern 1.{{ groupId:variableKey }}— a single member of a global-variable group. See Global variables → Pattern 1.
inputType: binding binds a deployment variable to a container environment variable at deploy time — the value never lands in quix.yaml.
inputType: ProjectVariable+variableKey— one project variable. See Project variables → Pattern 2.inputType: VariableGroup+variableGroupId— an entire global-variable group, injected as one environment variable per member. See Global variables → Pattern 2.
Both patterns can appear on the same deployment:
deployments:
- name: my-service
resources:
replicas: {{REPLICAS}} # {{ }} — substituted into the YAML at sync
variables:
- name: DB
inputType: VariableGroup # binding — resolved into the container at deploy
variableGroupId: redis-config
When each one resolves
{{ }} substitution |
inputType: binding |
|
|---|---|---|
| Resolved at | Sync — baked into the rendered descriptor | Deploy — injected into the container |
| Committed to Git | No — only the {{ }} token is committed, never the resolved value |
No |
| Visible in the sync diff | Yes — the resolved value renders in the before/after comparison shown when you sync | No |
| Applies to | Any quix.yaml field (cpu, replicas, urlPrefix, disabled, and so on) |
Container environment variables only |
| Reaches your code as an env var | No, not by itself | Yes |
| Picking up a changed value | Sync the environment | Redeploy — the binding resolves again at deploy time. Syncing the environment detects the change and restarts the deployment for you |
| Secrets allowed | No | Yes |
Because {{ }} resolves at sync time, the resolved value renders in the sync diff — the before/after comparison shown when you sync — while the file Git actually stores keeps the {{ }} token itself, never the value. (The YAML editor in the sync dialog also shows tokens rather than values; only the diff renders them resolved.) The next rule follows from that diff, not from Git.
Why secrets are never substituted
A secret project variable, or a secret member of a global-variable group, is never resolved through {{ }} — doing so would render the secret's plaintext in the sync diff. Both sides reject the reference at sync time:
- Project variable — the sync fails with:
Secret project variables ('MY_SECRET') cannot be referenced via {{ }} template syntax. Use inputType: ProjectVariable with variableKey instead. - Global-variable member — the sync dialog's
Unresolved variable groupsstep reports "Secret variables cannot be used in YAML templates", with the remediation "Remove the secret reference from the YAML. Secret values are never displayed."
Use an inputType: binding instead. The fix looks different on each side:
- Project variable — the secret is one key among many, so switch just that key to
inputType: ProjectVariablewithvariableKey. Every other{{ }}reference stays as it was. - Global-variable member — there is no per-member binding:
inputType: VariableGroupinjects the entire group. That binding is additive — it leaves every existing{{ groupId:variableKey }}reference untouched, and the two resolve independently. Add the group binding alongside the remaining template references rather than replacing them.
Where references work
Not every file resolves every reference:
quix.yaml— both patterns work.{{ }}substitution resolves in any field, andinputType:bindings sit under a deployment'svariables:.app.yaml— an application can define a variable group, including its identifier and the nested schema of the variables inside it, and every deployment of that application inherits the reference.{{ groupId:variableKey }}substitution, however, is not resolved inapp.yaml, nor in a code sample'slibrary.json. Keep group-member substitutions inquix.yaml.- Quix CLI — the CLI can substitute a colon-bearing token such as
{{ groupId:variableKey }}when a local.quix.yaml.variablesfile supplies a value for that exact token. It does not fetch or resolve Quix Cloud variable-group assignments; Cloud resolves those when you sync an environment.
When container environment-variable names collide
Collisions apply only to values injected into the container environment — literal environment variables, inputType: ProjectVariable, and inputType: VariableGroup. {{ }} substitutions change descriptor fields and do not participate.
Use one owner for every injected environment-variable name. In particular, do not bind groups with overlapping member keys: their iteration order is not a public contract, so the result must not be relied on.
Quix does not validate these overlaps, so avoid them rather than attempting to establish a precedence order. If a collision does slip through, the value that reaches the container today comes from the variable group — bindings are merged after project variables, which are merged after literal values — but that ordering is an implementation detail, not a guarantee.
A complete example
This deployment uses both routes at once. Two project variables, CPU and MEMORY, size it; the shared release-tiers group supplies its replica count; and the shared redis-config group provides its connection settings.
What you write in quix.yaml:
deployments:
- name: Order processor
application: order-processor
deploymentType: Service
resources:
limits:
cpu: {{CPU}} # project variable
memory: {{MEMORY}} # project variable
replicas: {{release-tiers:REPLICA_COUNT}} # global-variable group member
variables:
- name: redis
inputType: VariableGroup # the whole redis-config group
variableGroupId: redis-config
required: true
What the sync renders, in an environment where CPU is 200, MEMORY is 500, and release-tiers resolves REPLICA_COUNT to 3:
resources:
limits:
cpu: 200
memory: 500
replicas: 3
variables:
- name: redis
inputType: VariableGroup
variableGroupId: redis-config
required: true
The three {{ }} fields now hold values; the binding is untouched, because it is still a reference. The quix.yaml committed to Git keeps all four lines exactly as you wrote them.
What reaches the container, at deploy time, from the value set that redis-config is assigned in this environment:
REDIS_HOST=prod.redis.example.com
REDIS_PORT=6379
REDIS_PASSWORD=<the group's secret value, decrypted>
CPU, MEMORY, and REPLICA_COUNT are absent from that list. Substitution changes the deployment's configuration; only a binding reaches the deployment's environment.
Related documentation
- Environment variables — runtime configuration basics, value sources, and code examples.
- Project variables —
{{ }}andinputType: ProjectVariablein full, including validation errors and recipes. - Global variables — variable groups, value sets,
inputType: VariableGroup, and{{ groupId:variableKey }}in full. - YAML 1.0 and 2.0 — how
app.yamlandquix.yamlcompute the descriptor these variables end up in.