Environment variables
Give a service its configuration and secrets: set variables one at a time or from a .env file, decide whether the build or the running container sees them, and read the variables HostStack sets for you.
How variables work
Each service has its own set of variables. Every value is encrypted at rest with AES-256-GCM, whether or not you mark it secret. A variable reaches your code the next time the service deploys — changing one does not restart anything by itself, so deploy afterwards (or push a commit) to pick it up.
Variables can also come from an env group shared across services, from a linked database, and from HostStack itself. Which one wins when two set the same key is covered under Precedence.
Set a variable
In the dashboard, open the service, go to Settings → Variables, and fill in the row at the bottom of Service Variables: key, value, Inject into and the Secret switch. From a terminal:
# Create or update — the CLI looks the key up and updates it if it exists
hoststack env set svc_... NODE_ENV=production
hoststack env set svc_... STRIPE_SECRET_KEY=sk_live_... --secret --target runtime
hoststack env list svc_...
hoststack env get svc_... NODE_ENV
hoststack env delete svc_... NODE_ENVimport { HostStack } from '@hoststack.dev/sdk';
const hs = new HostStack({ apiKey: process.env.HOSTSTACK_API_KEY! });
const teamId = 1; // "Team ID" in the output of: hoststack whoami
// create() fails with 409 if the key already exists — use update() for that.
await hs.envVars.create(teamId, 'svc_...', {
key: 'STRIPE_SECRET_KEY',
value: 'sk_live_...',
target: 'runtime',
isSecret: true,
});
// update() and delete() take the variable's numeric id, from list().
const { envVars } = await hs.envVars.list(teamId, 'svc_...');Set STRIPE_SECRET_KEY on the service svc_... as a runtime-only
secret, then redeploy it.Keys are case-sensitive and stored exactly as you write them: they must start with a letter or underscore and contain only letters, digits and underscores, up to 256 characters. FOO and foo are two different variables, as they are inside the container. A value can be up to 32,768 characters.
Build, runtime or both
Every variable has a target that decides who can read it. The dashboard calls it Inject into; the CLI, SDK and API call it target.
| Target | Dashboard | Who sees it |
|---|---|---|
| both | Build + Runtime | The running container, and the build — unless the variable is also secret. This is the default. |
| runtime | Runtime only | Only the running container. Never reaches the build. |
| build | Build only | Only the build, and withheld from the running container. Honoured for secrets too: this is how you hand a build a private-registry token. |
A secret on both is runtime-only. Values given to a build can end up in the image's history, so HostStack never sends a secret to the build unless you choose Build only for it explicitly.
Secrets
Mark a variable Secret (--secret in the CLI, isSecret: true in the SDK) and its value is replaced by •••••• in the dashboard, in hoststack env list and in every API response. Your app still receives the real value.
The eye icon next to a secret in the dashboard reveals it. Every reveal is recorded in the team's activity log with who, when and from which IP address.
Import a .env file
The CLI and SDK send the file to HostStack, which reads it strictly: a line whose meaning depends on the reader — an unquoted $ as in a bcrypt hash, an unquoted #, a key written twice — is refused with its line number instead of guessed at. Nothing is written until you pass --apply.
# Dry run: prints what would be added, changed or refused
hoststack env import svc_... .env.production
# Write it. Imported variables are runtime-only secrets unless you say otherwise.
hoststack env import svc_... .env.production --apply
# Also delete every variable that is not in the file
hoststack env import svc_... .env.production --apply --replaceAfter an apply, every value is read back from storage and compared byte for byte with the file. The import refuses PORT and any HOSTSTACK_* key, because HostStack sets those itself on every deploy. At most 1,000 variables per file. Use --target and --no-secret to change the defaults.
The dashboard's Import .env button, on the same Variables tab, parses pasted text in the browser and merges it — or replaces everything when Replace all existing variables is on.
Secret files
For credentials that have to be a file — a TLS key, a service-account JSON, a .npmrc — use Settings → Secrets on the service. Give the file a display name, the absolute path to mount it at (for example /etc/ssl/cert.pem), and its content.
- The file is mounted read-only into the running container on the next deploy.
- Its content is encrypted at rest and never shown again after you save it.
- Files are limited to 1 MB of base64-encoded content, roughly 750 KB of file. The path must start with
/and may not contain... - Secret files are not available during the build.
Variables HostStack sets
Every deploy sets these in the container. You don't set them, they refresh on each deploy, and they override a variable of the same name that you set yourself.
PORTnumberThe port your app must listen on, on
0.0.0.0. HostStack routes to and health-checks exactly this port, so binding anything else fails the deploy. It is the port in the service's settings (or aport:in hoststack.yaml),3000unless you changed it.HOSTSTACK_COMMIT_ SHA stringThe full 40-character commit this deploy built. Absent when the deploy has no commit, so fall back rather than assume it is set.
HOSTSTACK_COMMIT_ SHORT_ SHA stringThe same commit, first 7 characters.
HOSTSTACK_RELEASE stringThe same commit again, under the name error reporters look for. Send it as
releasewhen you report an error, and each report is labelled with the code of the container that raised it — not whichever deploy happened to be live when it arrived.HOSTSTACK_BRANCH stringThe branch this deploy was built from.
HOSTSTACK_DEPLOY_ ID stringThe deploy's id (
dpl_…). Unique per deploy, so it tells apart two deploys of the same commit.HOSTSTACK_SERVICE_ NAME stringThe service's name, as shown in the dashboard.
HOSTSTACK_SERVICE_ ID stringThe service's stable id (
svc_…).HOSTSTACK_PROJECT_ ID stringThe numeric id of the project the service belongs to.
HOSTSTACK_TEAM_ ID stringThe numeric id of the team that owns the service.
HOSTSTACK_INTERNAL_ URL stringThe service's platform hostname, such as
web-a1b2.hoststack.dev— a bare hostname with no scheme. Despite the name, it is the public address, not a private one. To call another service privately, use the*_INTERNAL_URLvariables described under Networking.HOSTSTACK_TMP_ DIR stringA writable scratch directory. The container's root filesystem is read-only;
/tmpis memory-backed and emptied whenever the container is replaced. Use a volume for anything you need to keep.Default:
/tmpHOSTSTACK_DEV_ HOST stringDev boxes only: the box's public dev URL hostname, for your dev server's allowed-hosts list.
HostStack also sets *_INTERNAL_URL for each sibling service and DATABASE_URL-style variables for linked resources. Those are different: your own value for the same key wins, and an empty value switches them off. See Networking.
Report the live version
The usual reason to reach for these is to say which version is running:
import os
COMMIT = os.getenv("HOSTSTACK_COMMIT_SHA", "unknown")
@app.get("/version")
def version():
return {"commit": COMMIT, "deploy": os.getenv("HOSTSTACK_DEPLOY_ID")}The commit is also passed to your image build as the build argument HOSTSTACK_COMMIT, for when it must be baked in at build time — stamping a version into a compiled frontend bundle, for example. Declare ARG HOSTSTACK_COMMIT in your own Dockerfile, or use $HOSTSTACK_COMMIT in the service's build command.
Reference other resources in a value
A value can contain a template that HostStack fills in at deploy time, in build and runtime variables alike:
| Template | Becomes |
|---|---|
| ${{databases.<ALIAS>.<field>}} | A field of a linked resource, by its link alias: url (or connectionString), host, port, database, username, password. |
| ${{services.<name>.<field>}} | A sibling service's private address, by its slug or name: url, host or port. |
| ${{service.url}} | This service's own public address — its primary custom domain once one is active, otherwise its *.hoststack.dev hostname. ${{service.host}} is the same without the scheme. |
hoststack env set svc_... 'READ_REPLICA_URL=${{databases.REPLICA.url}}'
hoststack env set svc_... 'WEBHOOK_URL=${{service.url}}/hooks/stripe'A template that doesn't resolve — a typo in the alias or field — is left in the value exactly as written, so you can spot it rather than get an empty string. Adding a custom domain redeploys the service, which moves ${{service.url}} onto it.
Precedence
When the same key comes from more than one place, the higher row wins:
| # | Source |
|---|---|
| 1 | Variables HostStack sets — PORT and HOSTSTACK_* |
| 2 | Variables set on the service |
| 3 | Env groups, in their own order |
| 4 | Sibling *_INTERNAL_URL variables and linked-resource variables such as DATABASE_URL |
| 5 | env: in hoststack.yaml |
Next steps
Was this page helpful?