Documentation

envnest CLI

Secure environment variable management for teams and CI/CD. Everything you need to install, configure, and use the CLI.

Installation

One-line installer (all platforms)

$ curl -fsSL https://dl.envnest.dev/cli/install.sh | sh

macOS (Homebrew)

$ brew tap envnest/envnest
$ brew install envnest

Linux (Deb/RPM)

Download the .deb or .rpm from dl.envnest.dev, then install:

$ sudo dpkg -i envnest_*_linux_amd64.deb
# or
$ sudo rpm -i envnest_*_linux_amd64.rpm

Windows

Download the Windows zip from dl.envnest.dev, extract, and add envnest.exe to your PATH.


Uninstall

macOS (Homebrew)

$ brew uninstall envnest
$ brew untap envnest/envnest

Linux (Deb)

$ sudo dpkg -r envnest

Linux (RPM)

$ sudo rpm -e envnest

Manual install / one-line installer

$ rm -f $(which envnest)

Clean up local data

Remove cached credentials and saved context:

$ rm -rf ~/.envnest

Quick Start

1. Log in with your API token (generate one from the envnest dashboard):

$ envnest auth login --token <your-token>
✔ Login successful

2. Set your working context:

$ envnest context set
> Select organization:
  ▸ Acme Corp
    Personal
> Select project:
  ▸ billing-api
    frontend
> Select environment:
  ▸ production
    staging
    dev
✔ Context saved

3. Start managing secrets:

$ envnest secret list
+-----------------+-----------+----------+--------------+
| Key             | Value     | Version  | Updated      |
+-----------------+-----------+----------+--------------+
| DB_PASSWORD     | ********  | 3        | 2 hours ago  |
| API_KEY         | ********  | 1        | 5 days ago   |
| JWT_SECRET      | ********  | 2        | 1 month ago  |
+-----------------+-----------+----------+--------------+

Resource Hierarchy

envnest organizes resources in a three-level hierarchy:

Organization
+-- Project
    +-- Environment
        +-- Secrets
  • Organization — Your team or company. You can belong to multiple organizations.
  • Project — A service or application (e.g., billing-api, frontend).
  • Environment — A deployment stage (e.g., production, staging, dev). Each environment has its own set of secrets.

Most commands require all three levels. Set them once with envnest context set or pass them per command with --org, --project, and --env flags.


Secret Lifecycle

set (v1) → update (v2) → update (v3) → soft-delete → restore → rollback (v2)
                                              |
                                              +-- permanent delete (irreversible)
  • Every change creates a new immutable version. Nothing is ever silently overwritten.
  • Soft-delete preserves history so you can restore accidentally deleted secrets.
  • Permanent delete is irreversible and removes all version history.
  • Leak detection warns you if a secret value appears in known data breaches.

Authentication

# Log in with API token
$ envnest auth login --token <your-token>
✔ Login successful

# Log in with username and password
$ envnest auth login
> Email: alice@acme.io
> Password: ****
✔ Login successful

# Check current session
$ envnest auth whoami

# Log out
$ envnest auth logout

Context Management

Set your default organization, project, and environment so you don't need to pass flags every time.

# Interactive selection
$ envnest context set

# With flags
$ envnest context set --org=Acme --project=billing-api --env=production
✔ Context saved

# View current context
$ envnest context show
+--------------+------------------+
| Field        | Value            |
+--------------+------------------+
| Organization | Acme Corp        |
| Project      | billing-api      |
| Environment  | production       |
| Profile      | default          |
+--------------+------------------+

# Clear saved context
$ envnest context clear
✔ Context cleared

Organizations

# List your organizations
$ envnest org list
+-------------+---------------+----------+
| ID          | Name          | Plan     |
+-------------+---------------+----------+
| 9e2f1a3b-.. | Acme Corp     | Team     |
| b4c5d6e7-.. | Personal      | Free     |
+-------------+---------------+----------+

# Switch default organization
$ envnest org use 9e2f1a3b-...
✔ Default organization set to Acme Corp

Projects

# List projects
$ envnest project list
+--------------+-------------+--------------+
| ID           | Name        | Environments |
+--------------+-------------+--------------+
| a1b2c3d4-..  | billing-api | 3            |
| f8e7d6c5-..  | frontend    | 2            |
+--------------+-------------+--------------+

# Create a project (auto-creates a "dev" environment)
$ envnest project create --name "Billing API" --description "Payments service"
✔ Project created

# Set default project
$ envnest project use a1b2c3d4-...
✔ Default project set to Billing API

# Delete a project
$ envnest project delete a1b2c3d4-...
> Are you sure you want to delete project "Billing API"? (y/n): y
✔ Project deleted

Environments

# List environments
$ envnest env list
+-------------+------------+-----------+-----------+
| ID          | Name       | Secrets   | Protected |
+-------------+------------+-----------+-----------+
| e5f6g7h8-.. | production | 24        | Yes       |
| h8i9j0k1-.. | staging    | 18        | No        |
| l2m3n4o5-.. | dev        | 12        | No        |
+-------------+------------+-----------+-----------+

# Create an environment
$ envnest env create --name staging --description "Pre-production"
✔ Environment created

# Protect an environment (restricts writes, requires approvals)
$ envnest env protect production
✔ Environment protected

# Remove protection
$ envnest env unprotect production
✔ Environment unprotected

Secrets

List and read

# List all secrets (values masked)
$ envnest secret list

# Show decrypted values
$ envnest secret list --show

# Get a single secret
$ envnest secret get DB_PASSWORD --show

Create and update

# With inline value
$ envnest secret set DB_PASSWORD --value "new-secret-pass"
✔ Secret saved

# Prompted input (value hidden)
$ envnest secret set DB_PASSWORD
> Enter value: ****
✔ Secret saved

# From stdin (piped)
$ echo "super-secret" | envnest secret set DB_PASSWORD
✔ Secret saved

envnest checks new values against known data breaches:

$ envnest secret set DB_PASSWORD --value "password123"
⚠  Warning: This value has appeared in known data breaches.
> Proceed anyway? (y/n): n
✗ Aborted

Optional metadata flags: --description, --group, --data-type.

Delete and restore

# Soft delete (recoverable)
$ envnest secret delete API_KEY
✔ Secret deleted (can be restored)

# Permanent delete (irreversible)
$ envnest secret delete API_KEY --permanent
⚠  This will permanently delete API_KEY and all version history.
> Are you sure? (y/n): y
✔ Secret permanently deleted

# Restore a soft-deleted secret
$ envnest secret restore API_KEY
✔ Secret restored

Version history and rollback

$ envnest secret history DB_PASSWORD
+---------+---------------------+---------------+
| Version | Updated             | Updated By    |
+---------+---------------------+---------------+
| 3       | 2025-12-01 10:30:00 | alice@acme.io |
| 2       | 2025-11-15 08:00:00 | bob@acme.io   |
| 1       | 2025-10-01 12:00:00 | alice@acme.io |
+---------+---------------------+---------------+

$ envnest secret rollback DB_PASSWORD --version 2
✔ Secret rolled back to version 2

Risk analysis (AI)

Analyze your secrets for risk signals. No secret values are exposed, only metadata.

$ envnest secret analyze --include leaks,age

Available signals: leaks, age, shared_keys, suspicious_keys.


Secret Sharing

Create secure, time-limited links to share secrets with teammates or external collaborators.

# Share a single secret
$ envnest share create --secret DB_PASSWORD --expires 2026-12-31T23:59 --max-views 3
✔ Share created
  URL: https://envnest.com/share/abc123

# Share an entire environment with password protection
$ envnest share create --expires 2026-12-31T23:59 --password "share-pass"
✔ Share created
  URL: https://envnest.com/share/def456
OptionDescriptionDefault
--secret <key>Share a single secret (omit for entire environment)Entire env
--expires <datetime>Expiration (RFC3339 or YYYY-MM-DDTHH:MM)Required
--max-views <n>Maximum number of views1
--password <pass>Password-protect the linkNone
--same-orgRestrict access to same organizationOff
# List your shares
$ envnest share list
+--------------+-------------+-----------+---------------+
| ID           | Secret      | Views     | Expires       |
+--------------+-------------+-----------+---------------+
| s1a2b3c4-..  | DB_PASSWORD | 0/3       | 2026-01-31    |
| d5e6f7g8-..  | (env)       | 1/1       | 2026-02-15    |
+--------------+-------------+-----------+---------------+

# Revoke a share
$ envnest share revoke s1a2b3c4-...
✔ Share revoked

Sync

Sync secrets between local files and envnest. Supports .env, JSON, and YAML formats.

Push

$ envnest sync push --file=.env
✔ 12 secrets pushed

# Overwrite existing keys
$ envnest sync push --file=secrets.json --sync
✔ 8 secrets synced (3 created, 5 updated)

Pull

$ envnest sync pull --file=.env
✔ Secrets written to .env

$ envnest sync pull --format yaml --file secrets.yaml
✔ Secrets written to secrets.yaml

Diff

$ envnest sync diff --file=.env
+-----------------+----------+------------------+------------------+
| Key             | Status   | Local            | Remote           |
+-----------------+----------+------------------+------------------+
| API_KEY         | changed  | sk_live_new...   | sk_live_old...   |
| NEW_KEY         | added    | some-value       | -                |
| OLD_KEY         | removed  | -                | legacy-value     |
+-----------------+----------+------------------+------------------+

# Get an AI-powered explanation
$ envnest sync diff --file=.env --ai

Inject

Load secrets directly into a running process. No files are written to disk.

# Run a command with secrets as environment variables
$ envnest inject -- npm start
✔ 12 secrets injected into process

# Start a subshell with all secrets loaded
$ envnest inject --shell
Entering subshell with 12 secrets loaded...
$ echo $DB_PASSWORD
super-secret-pass
$ exit

Secret references like ${OTHER_KEY} are resolved automatically. Disable with --resolve=false.


Framework Guides

How to use envnest with your framework. Choose the approach that fits your setup.

Node.js / Bun / Deno

Inject secrets directly into your process:

$ envnest inject -- npm start
$ envnest inject -- bun run dev
$ envnest inject -- deno run server.ts

Laravel (PHP)

Laravel reads environment variables from the .env file. Use sync pull to generate it:

# Generate .env from envnest secrets
$ envnest sync pull --file .env

# Then start your app normally
$ php artisan serve

Why not inject? If you use Laravel Valet or PHP-FPM, they run as separate system processes that cannot receive injected environment variables. Use sync pull instead.

If you use php artisan serve (no Valet), you can use inject:

$ envnest inject -- php artisan serve

Go

$ envnest inject -- go run .
$ envnest inject -- ./my-go-binary

Rust

$ envnest inject -- cargo run
$ envnest inject -- ./target/release/my-app

Python / Django / Flask

$ envnest inject -- python manage.py runserver
$ envnest inject -- flask run
$ envnest inject -- uvicorn main:app

Ruby / Rails

$ envnest inject -- rails server
$ envnest inject -- bundle exec puma

Docker

# Write .env file, then pass it to Docker
$ envnest sync pull --file .env
$ docker run --env-file .env my-image

CI/CD

Use sync pull to generate an .env file in your pipeline:

$ envnest auth login --token $ENVNEST_TOKEN
$ envnest sync pull --file .env --org my-org --project my-app --env production

Interactive subshell

For any framework, you can open a subshell with all secrets loaded and run commands manually:

$ envnest inject --shell
✔ 12 secrets injected into process
$ echo $DB_HOST
127.0.0.1
$ npm start  # or any command — all inherit the secrets

KMS (Key Management Service)

Perform cryptographic operations with server-managed keys. All data is base64-encoded. KMS commands only require --org (no project or environment needed).

# Encrypt
$ envnest kms encrypt my-kms-key --plaintext SGVsbG8=

# Decrypt
$ envnest kms decrypt my-kms-key --ciphertext BASE64_CIPHERTEXT

# Sign
$ envnest kms sign my-kms-key --data SGVsbG8= --signing-algorithm RSASSA_PSS_SHA_256

# Verify
$ envnest kms verify my-kms-key \
    --data SGVsbG8= \
    --signature BASE64_SIGNATURE \
    --signing-algorithm RSASSA_PSS_SHA_256
✔ Signature valid

Team Management

Manage who has access to your organization.

# Invite a user
$ envnest user invite --email alice@example.com --role admin
✔ Invitation sent

# List users
$ envnest user list
+--------------+----------------------+--------+
| ID           | Email                | Role   |
+--------------+----------------------+--------+
| u1a2b3c4-..  | alice@example.com    | admin  |
| v5w6x7y8-..  | bob@example.com      | write  |
+--------------+----------------------+--------+

# Remove a user
$ envnest user remove v5w6x7y8-...
✔ User removed

Available roles: admin, write, read.


AI — Ask (CLI)

Ask natural-language questions about your secrets using AI. Only metadata is sent — no secret values are ever exposed to the model.

$ envnest ask "Which keys are shared between staging and prod?"
Found 1 shared key.
Items:
  - JWT_SECRET
Limitations: Metadata only.

More examples:

$ envnest ask "Total secrets" --project my-project --env production
$ envnest ask "List leaked secrets" --max-keys-per-env 200
$ envnest ask "Which secrets haven't been rotated in 90 days?"

To connect your AI coding tool (Claude Code, Cursor, Windsurf, Codex) directly to EnvNest via MCP, see the MCP Server reference.


Troubleshooting

Login issues

ProblemSolution
token is requiredRun envnest auth login --token <your-token>
401 Unauthorized on every commandYour token has expired. Run envnest auth login again
Forgot which account is activeRun envnest auth whoami to check

Context issues

ProblemSolution
organization is requiredRun envnest context set --org <org>
project is requiredRun envnest context set --project <project>
environment is requiredRun envnest context set --env <env>
Commands targeting the wrong projectRun envnest context show to verify, then envnest context set to fix

Permission issues

ProblemSolution
permission deniedYou don't have the required role. Ask your org admin to upgrade your access.
environment is protectedProtected environments require admin approval. Contact your admin.

Connection issues

ProblemSolution
connection refusedCheck your internet connection
Commands hang or timeoutCheck if envnest.com is accessible from your network

If you continue to experience issues, contact support at support@envnest.com.


Self-Hosted

Run the full EnvNest stack on your own infrastructure. Designed for regulated industries and security-conscious teams that cannot send secrets to a third-party cloud.

License: Commercial proprietary license. Distributed as pre-built Docker images. Commercial self-hosting requires an annual license. Plans start at $1,500/year.


Installation

Requirements: Docker Engine 24+, Docker Compose v2, 2 vCPU, 4 GB RAM, 20 GB disk.

Files are hosted in the GitHub repo under self-hosted/. No separate hosting required.

# 1. Download compose file and env template (GitHub raw)
curl -O https://raw.githubusercontent.com/envnest/envnest/main/self-hosted/docker-compose.yml
curl -O https://raw.githubusercontent.com/envnest/envnest/main/self-hosted/.env.example

# 2. Configure
cp .env.example .env
# Edit .env — see environment variables table below

# 3. Generate app key
docker compose run --rm app php artisan key:generate --force

# 4. Start all services
docker compose up -d

# 5. Run migrations and seed plans
docker compose exec app php artisan migrate --force
docker compose exec app php artisan db:seed --class=PlanSeeder

# 6. Import your license
docker compose exec app php artisan license:import

The app is available at http://localhost:8080. On first access the setup wizard guides you through license import, KMS selection, and admin account creation.

Environment Variables

App

VariableDefaultRequiredDescription
APP_KEYLaravel encryption key. Generate with php artisan key:generate
APP_URLhttp://localhostYour public domain e.g. https://secrets.acme.com
APP_ENVself-hostedMust be self-hosted
APP_DEBUGfalseMust be false in production
APP_NAMEEnvNestDisplayed in emails and UI

Database

VariableDefaultRequiredDescription
DB_HOSTdbPostgreSQL host (Docker service name)
DB_PORT5432PostgreSQL port
DB_DATABASEenvnestDatabase name
DB_USERNAMEenvnestDatabase user
DB_PASSWORDDatabase password

Redis

VariableDefaultRequiredDescription
REDIS_HOSTredisRedis host (Docker service name)
REDIS_PORT6379Redis port
REDIS_PASSWORDnullRedis password (optional)

Storage (MinIO)

VariableDefaultRequiredDescription
MINIO_ROOT_USERMinIO admin username
MINIO_ROOT_PASSWORDMinIO admin password (min 8 chars)
AWS_ACCESS_KEY_IDSame as MINIO_ROOT_USER
AWS_SECRET_ACCESS_KEYSame as MINIO_ROOT_PASSWORD
AWS_BUCKETenvnest-appPrimary storage bucket
AWS_ENDPOINThttp://minio:9000MinIO endpoint
AWS_USE_PATH_STYLE_ENDPOINTtrueMust be true for MinIO
AWS_DEFAULT_REGIONus-east-1Region (cosmetic for MinIO)

KMS

VariableDefaultRequiredDescription
KMS_DRIVERsoftwaresoftware | vault | aws
KMS_SOFTWARE_KEYBase64 32-byte key (software driver)
KMS_SOFTWARE_KEY_FILEPath to key file e.g. /run/secrets/kms_key (recommended)
KMS_VAULT_ADDRVault address e.g. https://vault.acme.com (vault driver)
KMS_VAULT_TOKENVault token (vault driver)
KMS_VAULT_KEY_NAMEenvnestVault Transit key name (vault driver)
AWS_KMS_DEFAULT_KEY_ARNKMS key ARN (aws driver)
AWS_KMS_ACCESS_KEY_IDAWS access key (aws driver)
AWS_KMS_SECRET_ACCESS_KEYAWS secret key (aws driver)

Mail (SMTP)

VariableDefaultRequiredDescription
MAIL_HOSTSMTP host
MAIL_PORT587SMTP port
MAIL_USERNAMESMTP username
MAIL_PASSWORDSMTP password
MAIL_FROM_ADDRESSFrom address e.g. no-reply@acme.com
MAIL_FROM_NAMEEnvNestFrom display name
MAIL_ENCRYPTIONtlstls or ssl

License

VariableDefaultRequiredDescription
LICENSE_KEYYour EnvNest self-hosted license key

AI (optional)

VariableDefaultRequiredDescription
OPENAI_API_KEYOpenAI API key. AI features are disabled if not set

OAuth / SSO (optional)

VariableDefaultRequiredDescription
GOOGLE_CLIENT_IDGoogle OAuth client ID
GOOGLE_CLIENT_SECRETGoogle OAuth client secret
GITHUB_CLIENT_IDGitHub OAuth client ID
GITHUB_CLIENT_SECRETGitHub OAuth client secret

KMS Options

DriverConfig keyBest for
software (default)KMS_SOFTWARE_KEY or KMS_SOFTWARE_KEY_FILESimple deployments
vaultKMS_VAULT_ADDR, KMS_VAULT_TOKENEnterprise with HashiCorp Vault
awsAWS_KMS_DEFAULT_KEY_ARNTeams already using AWS KMS

Set KMS_DRIVER=software|vault|aws in your .env.

Important: The KEK must be backed up separately from the database. Losing both simultaneously makes all secrets unrecoverable.

To rotate the software KEK:

docker compose exec app php artisan kms:rotate

License

Licenses are RSA-2048 signed offline keys — no phone-home required.

# Check current license
docker compose exec app php artisan license:show

# Verify signature and expiry
docker compose exec app php artisan license:verify

# Import a new or renewed license from file
docker compose exec app php artisan license:import /path/to/license.key

# Or pipe it in
cat license.key | docker compose exec -T app php artisan license:import

On expiry, a 14-day grace period applies before the instance enters read-only mode.


Upgrading

# Pull latest images
docker compose pull

# Restart services
docker compose up -d

# Run any new migrations
docker compose exec app php artisan migrate --force

Check the release notes before upgrading — breaking changes are flagged in UPGRADE.md.