Docs / Concepts

Concepts

Seven short ideas. Read them once and the CLI, the dashboard and the MCP server all make sense.

Services

A service is one app or deployment: its variables, how each applies, and the tokens that can read it. You make one per thing you run (web, worker, scraper-eu).

The dashboard and CLI still say process for a service: dynv admin add, DYNV_PROCESS, the Processes page. Same object. Names are encrypted in your browser, so we only ever see a random id.

Variables

A variable is a NAME=value pair. Names are letters, digits and _, cannot start with a digit or DYNV_, and are at most 256 bytes. Names and values are both encrypted on your machine before they leave it.

A service's whole configuration, names included, is stored as one encrypted document, so we cannot tell how many variables it has.

Live (hot) or restart, per variable

Every variable has an apply mode. A service's default is restart.

ModeWhat happens on a changeYour code
restartdynv run stops your process (SIGTERM, then SIGKILL after --grace seconds) and starts it again with the new env. About a second end to end.No changes. Reads process.env, os.environ, anything.
hotNothing restarts. dynv run updates a loopback agent, and the new value is there the next time your code asks.Reads through the SDK (or the local agent). A plain process.env read in a child started by dynv run keeps the value it started with.

If one change touches any restart variable, the process restarts once. If it touches only hot ones, it does not. Set the mode when you write, or change it later:

sh
dynv admin set web PROXY_SERVER=http://proxy.example:8000 --hot
dynv admin mode web restart DATABASE_URL

Removing a variable is remembered with a signed marker, so a deleted variable never falls back to a stale value from the environment your container started with.

Shared variables

A shared group holds variables you define once, for example PROXY_SERVER. You attach the group to the services that should use it. Change a value in the group once and every attached running service gets it live, hot or restart per variable, the same as today.

When the same name exists in more than one place, the service's own variable wins, then a group attached later, then a group attached earlier. Shared groups are encrypted the same way as everything else, so we still cannot read them.

Create one from Variables → New variable in the dashboard, or with dynv admin shared create and dynv admin shared attach. Detaching a service, or revoking one of its tokens, rotates the group's key, so it loses access immediately. A service needs a dynv from the current installer to receive shared variables; older versions keep working but ignore them.

Variable references

A variable can be marked as a template and built from other variables. ${NAME} is the value of another variable of the same service, including one from an attached shared group, and $$ is a literal $. Change DB_HOST once in a group and every service's DATABASE_URL follows, live.

sh
dynv admin set web --hot --template 'DATABASE_URL=postgres://${DB_USER}:${DB_PASS}@${DB_HOST}/app'
dynv admin show web    # the template, the (masked) result, and its apply mode

Only variables you mark as templates are resolved, so existing values that contain $ keep their meaning. Templates are resolved on your machines after decryption, so we still see nothing. A template can use other variables of the service and its groups, never the environment your container started with. A template is restart if it or anything it uses is restart. Dynv refuses a change that would break a template: a cycle, a name that doesn't exist, or removing a variable a template needs. If a template still breaks in a running service, the service keeps its last good value and logs the variable's name.

Tokens

Dynv has no usernames and passwords for machines. Access is by token, and there are two kinds.

TokenLooks likeWho holds itWhat it can do
Service tokendynv_pt_…One deployment. It becomes DYNV_TOKEN.Read exactly one service. Never write. Cannot see any other service: the keys for the others are never sealed to it.
Master tokendynv_mt_…You. Your recovery kit is one; so is each passkey, internally.Open your account's keys. A writer master token can change everything; a recovery or viewer one can only read. See roles.
  • One token per deployment (or per replica set), so a leaked one is revoked alone. Each shows when it was last seen.
  • Shown once. We store only a one-way hash of what proves you hold it, so we cannot show it again or recover it.
  • Revoking is immediate, and the service's data key is rotated in the same step, so nothing written afterwards is readable by the revoked holder. The running service keeps its last good env; revoking never takes a service down. Revoking does not un-leak what the holder already saw: rotate the upstream secret too.
  • dynv run removes DYNV_TOKEN from your app's environment. Only the supervisor holds it.

Scoped agent tokens for automation are Coming soon. Today an AI agent uses your master token through the local MCP server, with limits you set.

Members and roles

Invite people from Members in the dashboard. The invite is a link whose secret sits after the #, which browsers never send to a server; it works once and expires (24 hours at most for a viewer). There are three roles:

RoleCanCannot
OwnerEverything: create and delete services, change variables, mint and revoke tokens, invite people.-
RecoveryRead and export everything. Revoke any master token (to cut off a compromised owner).Write, invite.
Viewer (invited member)Read and export everything. Revoke their own devices.Write, invite, revoke anyone else.

Zero-knowledge: what we can and can't see

Encryption happens in your browser, the CLI or the MCP server, with keys derived from your tokens. The token secret is never sent to us; only a value derived from it that proves you hold it.

We can seeWe cannot see or do
Random ids, how many services and tokens you have, timestamps, which token fetched when and from which IP, rounded-up blob sizes (1 KiB buckets), audit events, and your email's keyed hash plus the address itself while sending you a code.Variable names or values. Service names. Token labels. How many variables a service has. Your passkey secret or any token secret. We also cannot forge or alter a service's variables: they are signed with a key we do not hold.

The audit log therefore records token, service id, time and IP, but never a variable name.

Runs when we're down

Dynv is not in your request path. Your service reads its env at start and then listens for changes.

  • Already running: keeps its env. Changes resume when Dynv is back.
  • Restarts while Dynv is down, with a cache: start with --cache /path/dynv.cache (or DYNV_CACHE). dynv run boots from the last version it received. The file holds ciphertext only, mode 0600.
  • Restarts while Dynv is down, no cache: it starts with the environment it already has (what your platform injects). Add --require to fail instead.
  • Stale or forged data: versions are signed and only go up. dynv run refuses an older version, or different content at a version it has seen, and keeps the last good env.
sh
dynv run --cache /var/lib/myapp/dynv.cache -- node dist/api.js

Limit: a server could withhold updates indefinitely, and a process with no cache can be served an old (but validly signed) version once at first boot. Both are covered in Security.

If you lose your keys

That is the cost of zero-knowledge: we cannot recover a lost master token or your recovery kit. Keep the recovery kit offline, and create a second recovery token with dynv admin master --out recovery.token if you want a spare.