Local Secrets
The local vault is the foundation of lpm env. It works without an account, without network access, on every plan. Values live in your OS keychain (Keychain on macOS, Secret Service on Linux, Credential Manager on Windows) and are scoped per project — moving or renaming the directory does not lose the vault, because each project gets a stable opaque vault-id written on first use.
Quick reference
lpm env set DATABASE_URL=postgres://... # write one
lpm env set FOO=bar BAZ=qux # write many
lpm env get DATABASE_URL # read (masked)
lpm env get DATABASE_URL --reveal # read (plaintext)
lpm env list # all keys (values masked)
lpm env list --reveal # all keys + values
lpm env delete FOO BAZ # remove one or more
lpm env import .env.production # import from a file (skips existing)
lpm env import .env --overwrite # import and overwrite
lpm env export .env.backup # export to a file
lpm env print # print for `eval $(lpm env print)`
Every read of a value defaults to masked output (DATABASE_URL=********). Pass --reveal to print the plaintext. The mask is friction by design — it stops accidental terminal scrollback or screen-share leaks.
Setting values
set accepts one or many KEY=VALUE pairs. Quoting rules follow your shell:
lpm env set API_KEY=sk-1234
lpm env set "GREETING=hello world"
lpm env set MULTI_LINE="$(cat private.pem)"
lpm env set FLAG_A=1 FLAG_B=2 FLAG_C=3
Setting an existing key overwrites it. To prevent that, use lpm env diff first or use a write-once import workflow with lpm env import (without --overwrite).
Reading values
lpm env get STRIPE_KEY # STRIPE_KEY=*********
lpm env get STRIPE_KEY --reveal # STRIPE_KEY=sk_test_abc...
lpm env list # all keys, all masked
lpm env list --json # JSON output for piping
To feed values to a shell, use lpm env print:
eval "$(lpm env print)" # export current vars into the shell
lpm env print --env=staging > .env.staging # write to a file
lpm run <script> and lpm dev inject the resolved environment automatically — you rarely need eval in practice.
Import / export
lpm env import .env # adds keys not already in the vault
lpm env import .env --overwrite # replaces existing keys
lpm env import .env.production --env=production # scoped import
lpm env export .env.backup # write all keys + values to file
lpm env export .env --env=staging # export one environment
Import understands the .env format (KEY=VALUE, # comments, quoted values). Export writes a plain .env file with plaintext values — treat the output the way you would any other secret. Pipe it to a co-worker through an encrypted channel; don't commit it.
Schema validation
If your project has an envSchema in lpm.json, lpm env check validates the local vault against it:
{
"envSchema": {
"DATABASE_URL": { "required": true, "format": "url", "secret": true },
"PORT": { "required": false, "default": "3000", "pattern": "^\\d+$" },
"API_KEY": { "required": true, "secret": true }
}
}
lpm env check # validate local
lpm env example # generate .env.example from the schema
check reports missing required keys, format mismatches, and pattern mismatches without revealing values. example writes a .env.example you can commit — keys only, no values.
lpm dev and lpm run honor the schema by default; pass --no-env-check to skip.
Where the data actually lives
macOS → Keychain item (service: dev.lpm.vault, account: <vault-id>)
Linux → libsecret / GNOME Keyring (same service / account)
Windows → Credential Manager (same service / account)
File fallback → ~/.lpm/.vault-data/<vault-id>.enc (mode 0o600, AES-encrypted)
The file fallback is automatic when no keychain is available (CI runners, headless servers, sandboxed environments). Force it for testing:
LPM_FORCE_FILE_VAULT=1 lpm env list
Initial setup
For a guided walkthrough that asks what environments you want and seeds a starter schema:
lpm env init # interactive setup
lpm env ls # show environments + counts
Listing environments and copying between them
lpm env ls # overview table
lpm env copy default staging # copy all keys from default → staging
lpm env copy staging production --env-rename --prefix STAGING_ # selective copy
The copy (alias cp) form copies an entire environment in one shot, which is faster than export | import. See Per-Environment Scoping for environment-level operations.
Next
- Per-Environment Scoping —
stagingvsproductionin one vault - Cloud Sync — push the local vault to lpm.dev (Pro/Org)
- Dashboard Pairing — read your vault from a browser