Variables & Secrets
Lizard stores configuration as secrets. They come in two scopes — service (the default) and project (--global) — and merge into your app’s environment in a defined precedence order. There is no workspace-level global scope.
Setting variables
lizard secrets set is variadic — set one or many at once. By default it writes to the linked service:
lizard secrets set DATABASE_URL=postgres://… LOG_LEVEL=info
lizard secrets set API_KEY=sk_live_… --service apiAdd --global to write to project scope (every service in the project sees it):
lizard secrets set NODE_ENV=production --globalListing, deleting, importing
lizard secrets list # current scope
lizard secrets list --show # reveal values
lizard secrets delete OLD_KEY ANOTHER_KEY # variadic
cat .env | lizard secrets import # import dotenv from stdinSee the lizard secrets command reference for every flag.
Scoping
| Scope | Command | Stored as | Visible to |
|---|---|---|---|
| Service (default) | lizard secrets set K=v --service <svc> | secrets.services[<svc>] | that service only |
| Project (global) | lizard secrets set K=v --global | secrets.shared | every service in the project |
Default to service scope. A compromised service can read its own environment — broader scope means more credentials exposed for no reason. Reserve --global for non-secret, provably-public values like LOG_LEVEL, NODE_ENV, feature flags, or a frontend SENTRY_DSN. If you’re unsure whether a value is a secret, treat it as one and scope it to the service.
For shared resources like a database, don’t put the DSN in --global — bind it per consumer with a reference:
lizard secrets set DATABASE_URL='${{postgres.DATABASE_URL}}' --service api
lizard secrets set DATABASE_URL='${{postgres.DATABASE_URL}}' --service workerRotation still happens once on the addon; every reference updates.
Precedence
When the same key is defined in multiple places, the last writer wins:
addon-issued env < project secrets < project env < app env < app secrets < platform varsSo app secrets override project secrets, and platform variables (PORT, LIZARD_SERVICE_NAME, LIZARD_PROJECT_ID, LIZARD_PUBLIC_DOMAIN) are applied last and cannot be shadowed.
Build-time vs. runtime
Most variable changes are pushed live to the running VM with no rebuild. The exceptions are build-time values baked into the image:
VITE_*andNEXT_PUBLIC_*changes force a rebuild on the next deploy.
See Build Pipeline → rebuild triggers.
Verifying
Confirm what a running service actually sees:
lizard ssh --service api -- envIf a value you expected isn’t there, see Troubleshooting → a secret or reference isn’t showing up.
Local development
Run a command locally with the service’s project + service secrets injected (handy for scripts and migrations):
lizard run --service api -- node scripts/seed.jsSee lizard run vs. lizard ssh.
See also
- Cross-Service References — read one service’s values from another without copy-pasting credentials.
lizard secrets— the full command reference.