VariablesVariables & Secrets

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 api

Add --global to write to project scope (every service in the project sees it):

lizard secrets set NODE_ENV=production --global

Listing, 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 stdin

See the lizard secrets command reference for every flag.

Scoping

ScopeCommandStored asVisible to
Service (default)lizard secrets set K=v --service <svc>secrets.services[<svc>]that service only
Project (global)lizard secrets set K=v --globalsecrets.sharedevery 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 worker

Rotation 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 vars

So 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_* and NEXT_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 -- env

If 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.js

See lizard run vs. lizard ssh.

See also