Introducing Via secrets and config

Via apps need runtime values that do not belong in source code. Some of those values are ordinary settings. Others are secrets. Via treats them differently.

The short version is simple. Plain config is for values that can appear in logs, support bundles, or command output. Secrets are for values that should not show up in argv, shell history, docker inspect, generated manifests, diagnostic JSON, or a copied runbook.

That split matters because deployed apps still need real values at runtime. A database URL is not source code. A session signing key is not a manifest field. If each app invents its own way to push those values into a process, the platform cannot audit the path, rotate the value, or explain why a deploy is blocked.

The runtime path

A Via app declares the secret names it needs in its app manifest. When the runner starts an app instance, it mints a short-lived workload token for that specific app, deploy, artifact, and runtime instance. The token names the secrets that instance may request.

Inside the container, the app gets two bootstrap values: the config server URL and the path to the workload token. When the app calls config.secret("DATABASE_URL"), the config server checks the token signature, audience, expiry, app id, deploy id, runtime instance, running state, and declared secret name before it reads the stored value.

If any part does not match, the request fails with a typed error. The app can tell the difference between a missing value, an undeclared secret, a denied request, and an unavailable config server. The config standard library page has the Vary-side API.

Safer operator commands

The CLI avoids putting secret values into the command text. For one secret, use the masked prompt:

vary app env set api DATABASE_URL --target prod --secret

For automation, redirect from an existing secret file or a CI secret store:

vary app env set api DATABASE_URL --target prod --secret < /run/secrets/api-database-url

For several values, use the template/apply flow. Fill the file in an editor, apply it, then remove the local copy:

vary app config template api --target prod --workdir . > api.prod.env
chmod 600 api.prod.env
$EDITOR api.prod.env
vary app config apply api --target prod --file api.prod.env
rm api.prod.env

The extra step is intentional. It keeps the secret out of command history and gives operators one local file to protect, apply, and remove.

Rotation without a source push

Secret rotation is a config operation, not a source change. vary app env rotate creates a new generation for a secret-backed env value. Running apps use a short runtime cache, so normal rotations become visible without rebuilding the artifact. If you need a stricter rollout boundary, use a config redeploy against the source commit that is already running.

The history and rotate commands are redacted. Operators see generations, timestamps, status, source, and provider metadata, not plaintext values.

Why this belongs in Via

Via owns the operational path around a Vary app: source intake, build, artifact signing, runtime identity, config delivery, routes, diagnostics, and audit. Secrets belong in that path because they are operational state. They should be declared by the app, stored by the platform, delivered through workload identity, and inspected through redacted tools.

The deeper reference is Secrets and config. Start there if you are wiring an app for deployment, debugging a missing secret, or deciding whether a value belongs in plain config or the secret store.