buidl

Guides

Secrets

Names in buidl.yaml. Values in files or the process environment.

env.secret lists names only. Values are resolved at deploy time, lowest precedence first:

SourceCommittedNotes
.env, .env.<environment>usuallyonly when env.dotenv: true
.buidl/secrets-commonyesindirections only: DATABASE_URL=$PROD_DATABASE_URL
.buidl/secretsnoall environments
.buidl/secrets.<environment>noone environment
process environmentn/aalways wins

The process environment outranks every file, so CI injection is never overridden by a leftover file on a laptop. A $VAR value looks up the environment. An unresolved indirection is treated as missing, not deployed as the literal string $VAR.

Values go into a Kubernetes Secret, never into buidl.yaml. A checksum of the resolved secrets is annotated on the pod template, so changing a secret value rolls the pods.

buidl variable list
buidl variable set DATABASE_URL=postgres://…
buidl variable set LOG_LEVEL=info --clear

variable (alias var / vars) prints each variable, its kind, and where it came from. Secrets show as set, N chars, never the value. Accessory secrets such as POSTGRES_PASSWORD are resolved from the same files even when they are not listed under the app’s env.secret; they are not injected into the app.

For secrets already in the cluster (External Secrets, Vault), use env.secretRefs.

env.dotenv: true reads .env and .env.<environment> for declared names only. A stray local variable cannot become part of a release. .env.local and .env.<environment>.local are never read.

buidl init adds .buidl/secrets and .buidl/secrets.* to .gitignore. It does not ignore .buidl/, because secrets-common and hooks are meant to be committed.

.buidl/
  secrets-common          committed, indirections only
  secrets                 gitignored
  secrets.production      gitignored
  hooks/
    pre-deploy            executable
    pre-deploy.sample     inert until you chmod +x