lpm env
Manage project environment variables and secrets — local-file storage, cloud sync, platform integrations, and OIDC policies.
lpm env set KEY=VALUE # set one or many vars
lpm env get KEY # read one (masked unless --reveal)
lpm env list # list all (masked unless --reveal)
lpm env delete KEY # remove
lpm env push # encrypt + push to lpm.dev
lpm env pull # pull + decrypt
lpm env push --to vercel # push to a connected platformlpm env manages encrypted environment variables for the project. Local secrets live in an OS-keychain-backed vault; cloud sync persists them to lpm.dev and platform integrations push them to Vercel, Netlify, Railway, and other connected providers.
For the underlying storage and encryption model, see Secrets vault.
Local-file management
lpm env list # list all vars (values masked)
lpm env list --reveal # list with values shown
lpm env get DATABASE_URL # get one var
lpm env get DATABASE_URL --reveal # get with value shown
lpm env set DATABASE_URL=postgres://... # set one
lpm env set FOO=bar BAZ=qux # set many at once
lpm env delete FOO BAZ # delete one or more
lpm env import .env.production # import from a file
lpm env import .env --overwrite # overwrite existing values
lpm env export .env.backup # export to a filePer-environment scoping
Pass --env=<name> to scope reads and writes to a named environment (e.g., staging, production). Environments are stored independently — staging and production keep separate value sets for the same key.
lpm env set --env=staging API_URL=https://staging.example.com
lpm env set --env=production API_URL=https://api.example.com
lpm env list --env=stagingOther local commands
lpm env init # interactive environment setup
lpm env ls # environment overview table with sync/update status
lpm env copy <src> <dst> # copy all secrets between envs
lpm env print # print resolved env (for `eval`)
lpm env check # validate against the project schema
lpm env example # generate `.env.example` from the schemaCloud sync
lpm env pull and lpm env push round-trip the local vault to lpm.dev's encrypted storage. The server only stores ciphertext — it never sees plaintext values.
lpm env push # encrypt + push the local vault
lpm env pull # pull + decrypt remote → local
lpm env diff # diff local vs remote (default env)
lpm env diff staging # diff local staging vs remote staging
lpm env diff staging production # diff two local environments
lpm env validate # check remote against the schema
lpm env share --org <org-slug> # share the vault with an org
lpm env pair <CODE> # pair this device via dashboard code (interactive confirmation)
lpm env pair <CODE> --yes # skip the confirmation prompt (NOT recommended)
lpm env unpair # revoke this device's pairing
lpm env log # last 50 audit log entries
lpm env rotate-key # rotate the vault wrapping key
lpm env rotate-sharing-key # rotate your X25519 sharing key (interactive, step-up reauth)Cloud sync is plan-gated. Free accounts get local-only storage; Pro/Org plans unlock push/pull/share.
Rotating your sharing key
lpm env rotate-sharing-key generates a fresh X25519 keypair, uploads the new public key under a vault:public-key:rotate step-up proof, and invalidates every org-vault wrapped-key entry the server held for you. The CLI keeps the new private key in a pending slot until the server has acknowledged the rotation, so a crash mid-flight is safe — re-running the command resumes the pending slot if the server already moved on. The flow:
- Prints the blast radius — every org vault you have access to needs an owner or admin to run
lpm env share --org <slug>before pulls resume. - Asks you to type
ROTATE(uppercase) to confirm. - Prompts for your password (and authenticator code, if MFA is enrolled) to mint the step-up proof.
- Uploads the new public key; the server invalidates the old wrapped-key rows and sends an out-of-band security email to your account plus an impact email to every affected org's owners and admins.
- Promotes the pending slot to the live keychain entry. The dashboard's vault Member Access view shows the affected rows as Needs share.
rotate-sharing-key refuses to run without a TTY — there's no --yes / non-interactive path, by design. On every machine where you want to keep pulling, you re-register the rotated key the next time the CLI needs it: any org-touching verb (env share, env pull --org, etc.) detects a missing server-side key and walks you through a vault:public-key:set step-up to register it.
The pre-rotation key never re-establishes itself. If a teammate's machine still has the old private key it cannot decrypt anything pushed under the new AES key, and the dashboard's audit log records the rotation with both fingerprints so cross-team forensics are trivial.
Platform integrations
Push the local vault out to deployment platforms — Vercel, Netlify, Railway, etc. — without copy/pasting values.
lpm env connect <platform> --project=<id> # link a platform project
lpm env push --to vercel # push current env to Vercel
lpm env push --to vercel --env=production --clean # replace platform values
lpm env pull --from vercel # pull from a platform
lpm env status # show connected platformsOIDC policies (CI)
Issue short-lived tokens to CI runs that prove repo identity, then exchange them for vault decrypt access — no long-lived tokens stored in CI secrets.
lpm env oidc allow --provider=github --repo=owner/repo --branch=main --env=production
lpm env oidc list # list configured policies
lpm env pull --oidc --env=production --output=.env # CI-side decryptlpm ci setup github-actions and lpm ci setup gitlab generate ready-to-paste snippets that wire OIDC and call lpm env pull --oidc automatically. The two providers expose OIDC differently:
- GitHub Actions — the GitHub runtime exposes
ACTIONS_ID_TOKEN_REQUEST_URL+ACTIONS_ID_TOKEN_REQUEST_TOKENto any job that declarespermissions: id-token: write, and the CLI fetches the JWT at run time. The emitted snippet relies on this — it does not setLPM_OIDC_TOKEN. - GitLab CI — the runtime has no equivalent of GitHub's runtime fetch, so the snippet mints
LPM_OIDC_TOKENvia theid_tokensblock withaud: https://lpm.dev. The CLI then routes it through the registry-exchange surface as a pre-supplied token.
You can also set LPM_OIDC_TOKEN by hand on either provider — for self-hosted GitHub runners that lack the runtime endpoint, or for any non-standard CI where you've fetched a https://lpm.dev-audience JWT some other way.
Flags
| Flag | Effect |
|---|---|
--env=<name> | Scope to a named environment (default: default) |
--reveal | Show values in get / list (default is masked) |
--overwrite | import overwrites existing keys instead of skipping |
--to <platform> | push target platform (vercel, netlify, …) |
--from <platform> | pull source platform |
--clean | Replace platform values instead of merging |
--yes | Skip confirmation prompts |
--oidc | Use OIDC token exchange (CI) instead of stored creds |
--output <file> | Write pull results to a file instead of the vault |
--org <slug> | Org-scoped sync target |
Plus the global flags.
See also
- Secrets vault — storage and encryption design, sharing-key lifecycle, CLI step-up reauth
lpm ci— generate CI YAML with OIDC wiringlpm.json—envSchemaand environment definitions