Environment variables
Environment variables are how a template configures the workload inside it: a Hugging Face token, a model name, a log level. Add them in the Environment section of the template form, one key and value per row, with a secret switch on the right.
Setting them
| Part | Rules |
|---|---|
| Key | Up to 256 characters. Rows with a blank key are dropped when you save. |
| Value | Any string. Leaving it empty stores the entry as unset. |
| Secret | Masks the value for anyone outside the owning organization. |
An entry with no value is not injected into the container at all. That makes it a good placeholder: declare HF_TOKEN as a secret with no value, and the template documents what a renter must supply without shipping a token to everyone who reads it.
Over the API, env is a list of objects on POST /v1/templates and PATCH /v1/templates/{id}:
{
"env": [
{ "key": "MODEL_ID", "value": "meta-llama/Llama-3-8B", "secret": false },
{ "key": "HF_TOKEN", "value": null, "secret": true }
]
}
Sending env on a PATCH replaces the whole list. There is no per-key update.
Secret masking
A secret value is returned only to the organization that owns the template. Everyone else — including someone browsing your public template, and including a curated system template's readers — gets value: null with the secret flag intact. The console shows the key with a hidden placeholder instead of the value.
The masking follows the data, not the endpoint: GET /v1/templates, GET /v1/templates/{id} and GET /v1/templates/by-hash/{hash_id} all apply it.
Two consequences worth knowing:
- Duplicating a template your organization does not own blanks every secret value in the copy. You never had read access to them, and becoming the copy's owner must not change that. Duplicating your own template keeps them.
- Marking an existing value secret hides it going forward, but does not un-share it with anyone who already read it. Rotate the credential instead.
Renter overrides at deploy
A deploy can add or replace environment entries with env_overrides on POST /v1/instances:
{
"offer_id": "…",
"template_id": "…",
"disk_gb": 100,
"env_overrides": [{ "key": "HF_TOKEN", "value": "hf_…", "secret": true }]
}
Template env is applied first, then the overrides, matched by key — the override wins. Entries with a null value on either side are dropped rather than injected as an empty string. This is how you fill a secret placeholder without editing the template, and it keeps your token off a shared recipe.
The platform overlay always wins
After the template env and the renter overrides are merged, Superheat applies a platform overlay, and the overlay is applied last. A key in the overlay cannot be shadowed by a template value or by an env_overrides entry — whatever you set is silently replaced.
| Variable | Set when | Carries |
|---|---|---|
CONTAINER_ID | always | the workload identifier |
GPU_COUNT | always | how many GPUs are assigned to this instance |
SUPERHEAT_TCP_PORT_<n> | per published TCP port | the host port that container port <n> maps to |
PUBLIC_KEY | ssh, jupyter, when you attach an SSH key at deploy | your SSH public key |
SUPERHEAT_SSH_PUBLIC_KEYS | ssh, jupyter, when you attach an SSH key at deploy | the same key material, in the newline-separated form |
SUPERHEAT_ONSTART | ssh, jupyter, when set | the on-start script body |
OPEN_BUTTON_PORT | ssh, jupyter, when a port is labeled open | the Open button target port |
JUPYTER_TOKEN | jupyter | the platform-minted access token |
JUPYTER_PORT | jupyter | 8080 |
JUPYTER_DIR | jupyter | the template's Jupyter working dir |
JUPYTER_LAB | jupyter | true for JupyterLab, false for the classic notebook |
So setting JUPYTER_TOKEN on a template does nothing: the platform mints the token so it can build the Open button URL, and the token never travels back up the wire. Setting GPU_COUNT does nothing either — it reflects the slice you actually rented, and a program that trusts it would be lied to if a renter could edit it.
The overwrite is silent. If your code reads GPU_COUNT expecting your own value, it will get the platform's instead, with no error anywhere.
What you see inside the container
On a base-derived image, sshd and Jupyter start login shells that do not inherit the container process environment, so the entrypoint writes the environment to /etc/environment and /etc/profile.d/superheat-env.sh. Your variables, plus CONTAINER_ID, GPU_COUNT and the SUPERHEAT_TCP_PORT_* entries, are all there when you SSH in.
Provisioning secrets are deliberately excluded from both files: SUPERHEAT_ONSTART, JUPYTER_TOKEN, PUBLIC_KEY and SUPERHEAT_SSH_PUBLIC_KEYS are consumed by the entrypoint and never re-exported. Echoing $JUPYTER_TOKEN in an SSH session returns nothing, and that is working as designed.