Skip to content

Ask AI

Ask anything about Destesi — setup, products, APIs.

Powered by Claude. Answers may be wrong — always verify against the docs.

Env templates

Preview resolves ${namespace.field} refs server-side against the forked Snap’s endpoints — so your compose services get concrete, per-PR DB coordinates with no client-side string-building.

The snap fork is created after you submit the preview, so the DSN isn’t known when you write the workflow. Template strings declared in your preview’s env list are resolved on the API just before the runner boots — unresolved refs surface as EnvError, never as empty strings.

Two sources, in precedence order:

  1. .destesi.yml at the repo root — when present with preview.enabled: true, its env list is authoritative. File ships with the PR; reviewers see env changes in the same diff. Full reference.
  2. Dashboard — the existing per-preview env editor. Used when no file is committed (or when the file’s preview: block is absent / disabled).

File-wins-strict — committing a file to a repo whose previews are dashboard-managed today will overwrite the dashboard env on the next build. Migrate by copying entries into the file in one PR.

  • Template is ${namespace.field}. Dotted names, not underscores.
  • Literals and multiple refs compose: ${postgres.user}:${postgres.password}@${postgres.host}.
  • Resolved values are not rescanned — no recursive templating.
  • Unknown namespace or field → EnvError, preview fails fast.
  • Mark a value secret: true (or --env-secret via CLI) to redact it from the web UI + API responses.
Reference Resolves to
${postgres.dsn} Full snap DSN (scheme+user+pass+host+port+db).
${postgres.host} Snap host. In-cluster Service address for pods; localhost for host-reach.
${postgres.port} Snap port.
${postgres.user} Snap user.
${postgres.password} Snap password.
${postgres.database} Snap database name.
${postgres.sslmode} sslmode carried from the remote’s DSN (empty when the DSN doesn’t set one).
${s3.*} Reserved; currently unresolved (future release).
${preview.*} Reserved; currently unresolved (future release).
Terminal window
dst preview create \
--env 'DATABASE_URL=${postgres.dsn}' \
--env 'PGHOST=${postgres.host}' \
--env-secret NEXTAUTH_SECRET=$(openssl rand -hex 32) \
--from-dir ./app --from-remote conn_abc
{
"identity_workspace_id": "ws_...",
"source_kind": "github",
"third_party_app_id": "...",
"repo_ref": "owner/repo",
"branch": "feat/x",
"env": [
{ "name": "DATABASE_URL", "value": "${postgres.dsn}" },
{ "name": "PGHOST", "value": "${postgres.host}" },
{ "name": "NEXTAUTH_SECRET", "value": "...", "secret": true }
]
}
  • Don’t set NEXTAUTH_URL for Auth.js apps. The overlay forwards X-Forwarded-Host / X-Forwarded-Proto; Auth.js with trustHost: true reads those. Hardcoding NEXTAUTH_URL pins one callback host and breaks preview URLs.
  • Host rewriting is automatic. The DSN the runner sees is rewritten from localhost:<nodeport> to the in-cluster Service address (snap-s-<id>.destesi-snaps.svc…) so DinD-nested containers can reach it. You get the right value either way.
  • Secrets are stored server-side. --env-secret NAME=value posts the value encrypted at rest and redacts it in all API/UI responses. Rotate by redeploying with a new value.
  • Declared env wins over compose’s environment: section. The runner generates a docker-compose.override.yml that injects declared env into every service, so you don’t have to ${VAR}-thread values through your compose file.