Managing secrets across environments
Store local values, validate environments, share project secrets, and rotate organization access.
Use lpm env to store project values outside plaintext dotenv files. Select an environment when you store or load its values.
lpm env set LOG_LEVEL=debug --env development
lpm env list --env development
lpm dev --env developmentLocal use does not require an LPM.dev Registry account. Cloud sync requires authentication and access to the env project.
Configure shared environment names
Keep shared configuration in lpm.json:
{
"tasks": {
"dev": { "env": "development" },
"start": { "env": "production" }
},
"envSchema": {
"vars": {
"DATABASE_URL": { "required": true, "format": "url" },
"API_KEY": { "required": true, "secret": true },
"LOG_LEVEL": { "default": "info", "pattern": "^(debug|info|warn|error)$" }
}
}
}These tasks use the existing package scripts. An explicit --env overrides the task environment.
lpm env maintains the literal vault identifier in lpm.json for project storage and sync. The identifier contains no secret and grants no access. Commit it.
Each checkout keeps its own sync state in .lpm/env-sync.json, which Git never sees. lpm env works from any directory in the project: it uses the nearest directory with a package.json or an lpm.json.
Store and inspect values
lpm env set API_URL=https://staging.example.com --env staging
lpm env set API_URL=https://api.example.com --env production
lpm env list --env staging
lpm env get API_URL --env staging --reveal
lpm env delete API_URL --env stagingLists mask values by default, regardless of envSchema.secret. --reveal prints actual values.
Values passed as command arguments can enter shell history. For existing secrets, import a protected file instead of copying its values into command lines.
Local storage uses the operating-system backend when available, with a protected file fallback in the LPM home (~/.lpm, or $LPM_HOME). Each LPM home has its own local secrets. See local secrets for the storage boundary.
Import or export a file
lpm env import .env.production --env production
lpm env import .env.production --env production --overwriteWithout --overwrite, existing stored keys keep their values. Import does not delete the source file. It adds a .gitignore rule for the file when Git doesn't already ignore it, and warns when Git already tracks it.
For a system that requires dotenv input:
lpm env export .env.production.export --env productionExports contain plaintext. The command writes the file owner-only and, when Git doesn't already ignore it, adds an anchored rule for its path to .gitignore first.
A destination that Git tracks stops the export, because an ignore rule can't untrack it. Run the git rm --cached command that the error names, then export again. If the rule can't be added inside a repository, the export stops and writes nothing.
Keep exports outside artifacts and logs. Delete temporary plaintext files after the receiving system imports them.
Load values into a command
lpm run start --env production
lpm dev --env stagingThe selected local environment overrides matching dotenv values. If that environment is missing or empty, runtime loading falls back to default.
A nonempty named environment does not inherit missing keys from the default local environment. File inheritance is a separate configuration feature.
Restart a running command after changing a value. Stored changes do not update an existing process environment.
Check the schema
lpm env check
lpm env check --jsonThe command checks discovered environments and returns nonzero for invalid values. JSON includes the per-environment results and success status.
| Schema field | Purpose |
|---|---|
required | Require a value. |
format | Check a supported URL, email, port, boolean, integer, hostname, or IP format. |
pattern | Require the value to match a regular expression. |
default | Supply a missing value during schema application. |
secret | Mark a value for supported redaction paths. |
The runner also checks the effective environment before project commands. --no-env-check skips value checks and schema defaults for one run. Invalid schema declarations still stop the command.
Compare with .env.example
lpm env validate
lpm env validate --strict --jsonThis separate check compares .env.example keys with the default local environment. It does not use envSchema or inspect remote cloud values.
Without --strict, extra stored keys are allowed. With --strict, extra keys also fail the check.
Inherit dotenv files
{
"environments": {
"base": { "file": ".env" },
"staging": { "extends": "base", "file": ".env.staging" },
"preview": { "extends": "staging", "file": ".env.preview" }
}
}lpm dev --env previewThis loads the configured files in inheritance order. Later values replace earlier values. Local secret selection still uses the selected environment's own rules.
Share an organization project
An owner or administrator must grant the contributor access and bind the contributor's registered sharing key.
On a configured contributor machine:
lpm login
lpm env pull --org acme
lpm env check
lpm devReplace acme with your organization slug. The checkout must identify the intended env project in lpm.json.
A personal account login does not transfer another device's encryption key. Browser pairing transfers a key to the browser, not to another CLI machine.
For a new local-only or personal device, transfer the required values through an approved secure channel, then import them locally.
See secrets sync for project-key trust, organization sharing, and cloud conflict handling.
Rotate organization access
After removing a member, rotate each affected env project from an authorized machine that can decrypt it:
lpm env rotate-key --org acmeIf the recipient set changed, the command prints the proposed recipients, sharing-key fingerprints, and acceptance digest.
Compare those identities and fingerprints with the intended recipients. After review, rerun with the exact displayed digest:
lpm env rotate-key --org acme --accept-recipient-keys <digest>Rotation includes current members with registered sharing keys. A member without a sharing key cannot receive the encrypted project key.
The server checks the current project version and recipient bindings before committing the rotation. A conflict preserves the previous remote state.
Rotation protects future encrypted state. It cannot erase values or keys that a former member already copied.
Load application secrets in CI
Configure env CI access before the job runs. Remote access needs the env project's own policy and credentials.
For OIDC access, configure LPM_OIDC_POLICY_ID, the env project selector, and the permitted workflow identity. Then pull the selected environment:
lpm env pull --oidc --env=production --output=.env.productionThe output file contains plaintext. LPM CLI writes it owner-only and, when Git doesn't already ignore it, adds a rule to the repository's .git/info/exclude, so the work tree stays clean. Keep the file out of logs and artifacts. A fresh runner does not inherit another machine's local encryption keys.
For GitHub Actions, mark secret values with envSchema.secret and apply the generated script without printing it:
- name: Load application variables for later steps
shell: bash
run: |
set +x
set -o pipefail
lpm env print --env production --ci | bashThis formats the resolved local project environment. It does not fetch remote secrets. GitHub applies the resulting values to subsequent steps.
print --ci produces shell commands on GitHub Actions, dotenv on Vercel, and shell exports otherwise. Printing that output alone does not configure a job.
See CI/CD setup for dependency credentials and the command reference for supported CI destinations.
Troubleshooting
| Problem | Action |
|---|---|
| Named environment misses a default key | Add it to that environment or use explicit file inheritance. |
| Schema check fails | Correct the selected values or schema. |
| Contributor cannot decrypt a project | Check project access and registered sharing-key bindings. |
| Recipient digest changed | Review the new recipient set before accepting it. |
| Cloud version conflict | Pull the current state, reconcile it, and retry. |
| Export stops because Git tracks the file | Run the git rm --cached command that the error names, then export again. If the file was ever pushed, rotate the exposed credentials. |
See also
- lpm env — commands and flags
- Local secrets — local storage and runtime loading
- Secrets vault — sync and encryption model
- lpm.json — environments and schemas