Skip to main content
Set environment variables and secrets once, at the organization level, and boxd injects them into every machine you own. This means into login shells, into the environment your boxd machine exec commands and coding agents run in, and into services your machine starts at boot. Every machine picks the values up on its own, without .env files to copy around. There are two kinds: Both are injected into your machines the same way. The difference is what happens at rest. Env var values are stored in cleartext and shown by list. Secret values are sealed and never returned by the API, not even to you. To change a secret you re-set it. Manage them from the CLI, the in-VM CLI, or the console.

Environment variables

Secrets

Secrets bound to a host

A secret can be bound to the hosts it may be sent to. The machine then only holds an opaque bxds_… placeholder, and the real value is inserted into requests to those hosts on the way out, never anywhere else. It is set from the SDK:
The real value never enters the machine. That changes what a secret is:
  • Nothing running inside can read it, log it, or send it elsewhere. Not an agent, not a prompt injection, not a compromised dependency. env, shell history, and agent transcripts only ever contain the placeholder.
  • The placeholder is useless anywhere else. Sent to any host you did not name, it is a meaningless string.
  • Rotating the value does not change the placeholder, so nothing inside needs to restart or know.
So you can give a machine the use of a key without giving it the key. That is what makes it fit for agentic SaaS and sandboxes: code you do not fully trust, or an agent acting for a customer, can call the customer’s API and still cannot walk away with the credential. Pair it with a per-machine egress allowlist to confine what the machine can reach at all. Both are covered in Egress control.

Host-bound secrets

A secret can be bound to the hosts it may be sent to. The machine then only ever holds a placeholder. The real value is substituted into requests to those hosts on the way out, and nowhere else.
Inside the machine, STRIPE_KEY is an opaque bxds_... string. A request to api.stripe.com carrying it, in a header, the query, the body or Basic auth, arrives at Stripe with the real key. A request anywhere else carries the useless placeholder. There is nothing to configure in the machine, the placeholder does not change when the value is rotated, and a process with root in the machine still cannot read the real value. --domains takes hostnames or wildcards such as *.stripe.com, comma-separated or repeated. Provider-wide wildcards such as *.amazonaws.com are refused. The hosts of a bound secret are always reachable from the machine, on top of any egress allowlist it has. The console offers the same on the Secrets page, as a hosts field on a secret and a Hosts column in the list, and the SDKs take domains on secrets.set. In the SDKs the list you pass is the complete set, so pass it again when rotating a value.

Naming

Names must be valid environment identifiers, made of letters, digits, and underscores, starting with a letter or an underscore. The BOXD_* prefix is reserved for boxd’s own variables.

Scope

The --scope flag decides which of the org’s machines receive the variable:

How they reach a machine

On boot, and again on every login shell, boxd resolves the env vars and secrets in scope for that machine and exports them. So they’re present for:
  • interactive shells (ssh <vm>.boxd),
  • boxd machine exec commands,
  • the pre-installed coding agents, and
  • services your machine starts at boot.
Add or rotate a value and new machines pick it up immediately. Already-running machines see it on their next boot profile refresh. An isolated machine gets them in exec and SSH sessions only, never at boot.