Core Commands

These commands handle the basic workflow of syncing environment variables between EnvManager and your local .env files.

pull

Download variables from EnvManager to a local file.

envmanager pull [options]

Options:

OptionDescription
-e, --environment <name>Environment name (default: from config or "development")
-p, --project <id>Project ID (default: from config)
-o, --output <file>Output file path (default: .env)
--format <type>Export format (see Export Formats)
--k8s-namespace <ns>Kubernetes namespace (default: "default")
--k8s-name <name>Kubernetes resource name
--no-secretsExclude secret values (will be empty)
-f, --forceOverwrite existing file without prompting
-r, --resolve-referencesResolve ${VAR} references to their values
-F, --include-fallbacksInclude fallback values for empty variables
-s, --show-sourcesShow value source as inline comments

Examples:

# Pull from configured project/environment
envmanager pull

# Pull specific environment
envmanager pull --environment production

# Pull to custom file
envmanager pull --output .env.local

# Pull without secret values
envmanager pull --no-secrets

# Pull as Docker Compose YAML
envmanager pull --format docker-compose -o docker-compose.env.yml

# Pull as Kubernetes Secret
envmanager pull --format k8s-secret --k8s-name my-app --k8s-namespace production -o secrets.yaml

Output:

Pulled 12 variables to .env (dotenv)
  8 plain, 4 secrets

For details on all supported export formats, see Export Formats.

push

Upload a local .env file to EnvManager. Existing variables are updated in place, new ones are added; nothing is deleted. The push is all-or-nothing: if anything fails, no variable is changed.

envmanager push [options]

Options:

OptionDescription
--org <name>Organization name (only needed if you belong to several)
-e, --environment <name>Environment name (default: from config or "development")
-p, --project <id>Project ID, friendly ID or name (default: from config)
-i, --input <file>Input file path (default: .env)
--secrets <keys>Comma-separated keys or patterns to mark as secrets (see below)
--plain <keys>Comma-separated keys or patterns to explicitly mark as plain — turns those secrets back into plain variables; other keys keep their flag
--all-secretsMark every variable in the file as a secret
--no-secretsMark every variable in the file as plain
--service <name>Push to a specific service instead of the shared variables
--createCreate the --service if it doesn't exist yet (owners and admins only)
--dry-runShow exactly what would happen without changing anything
--no-syncDon't trigger auto-sync to connected platforms after the push

Examples:

# Push from .env
envmanager push

# Preview first — shows target project, environment and service
envmanager push --dry-run

# Mark specific variables as secrets
envmanager push --secrets "DATABASE_URL,API_SECRET"

# Patterns: * matches anything, ? matches one character
envmanager push --secrets "STRIPE_*,*_SECRET,*_TOKEN"

# Push a different file to production
envmanager push --input .env.production --environment production

# Push to a service, creating it on the first run
envmanager push --service worker --create

# Turn PORT and LOG_LEVEL back into plain variables, keep everything else as is
envmanager push --plain "PORT,LOG_LEVEL"

# Both at once: STRIPE_* become secrets, NEXT_PUBLIC_* become plain
envmanager push --secrets "STRIPE_*" --plain "NEXT_PUBLIC_*"

How secrets are decided:

  • Keys matching --secrets become secrets. Matching is case-sensitive; * and ? are the only wildcards.
  • Keys matching --plain become plain variables, even if they are secrets today. Same pattern syntax.
  • Keys that match neither keep whatever they already are on the server. A key that is already a secret stays a secret even when you leave it out of --secrets. New keys are plain.
  • --secrets and --plain can be combined, but a key that matches both is an error.
  • --all-secrets makes everything a secret; --no-secrets makes everything plain. Neither can be combined with --secrets or --plain.
  • If an entry in --secrets or --plain matches no key in your file, you get a warning (not an error) so a typo doesn't go unnoticed.

Auto-sync:

After a successful push the CLI triggers auto-sync for every integration of the environment that has Auto-sync enabled (Vercel, Render, Railway, GitHub, ...), exactly like saving in the web app does. Only sync targets whose scope includes what you pushed are triggered: a push to the shared variables reaches every target, a push with --service api reaches "whole environment" targets and the api target. The outcome is printed under the summary:

✔ Pushed 12 variables to production
  3 inserted, 9 updated
  Auto-sync: render ✔
  Auto-sync: vercel ✖ Vercel token expired — reconnect the integration

A failed auto-sync does not fail the push (the variables are saved); open the integration page for details. Pass --no-sync to skip auto-sync, for example when you push several files in a row and want to sync once at the end. Nothing is printed when the environment has no auto-sync targets.

Changing whether a variable is secret:

Once a key is a secret it stays one until you say otherwise. To un-mark a few keys after an earlier --all-secrets push, use push --plain "KEY_A,KEY_B", or set a single key directly with envmanager set KEY=VALUE --no-secret (see set). The other direction works the same way: push --secrets or set KEY=VALUE --secret.

Empty values:

A secret can't be empty. If any key that would end up as a secret has an empty value, the push stops before anything is written and lists every offending key:

✖ Push aborted: 2 secrets have an empty value
  STRIPE_KEY
  DB_PASSWORD

Plain variables may be empty.

Dry run output:

✔ Dry run — no changes made

  Project:     acme-api
  Environment: production
  Service:     worker (will be created)
  Variables:   12  (3 new, 9 updated)
  Secrets:     STRIPE_KEY, DB_PASSWORD
  Un-marked:   PORT

Variables to push:
  PORT=3000
  STRIPE_KEY=•••••• [secret] [new]

A dry run performs every check the real push does (authentication, project/environment/service lookup, naming conventions, empty secrets), so a successful dry run means the push will succeed. The Un-marked line only appears when --plain is given and lists the keys that are secrets today and will become plain.

set

Set one or more variables directly from the command line, without a .env file. Existing keys are updated, new ones are created; nothing else in the environment is touched. Like push, the write is all-or-nothing.

envmanager set KEY=VALUE [KEY2=VALUE2 ...] [options]

Options:

OptionDescription
--org <name>Organization name (only needed if you belong to several)
-e, --environment <name>Environment name (default: from config or "development")
-p, --project <id>Project ID, friendly ID or name (default: from config)
--service <name>Set the variables on a service instead of the shared variables (default: service from config, if set)
--secretMark the variables as secrets
--no-secretMark the variables as plain — turns a secret back into a plain variable
--no-syncDon't trigger auto-sync to connected platforms after saving

Without --secret or --no-secret each key keeps the flag it already has on the server; new keys are plain. Like push, a successful set triggers auto-sync for integrations with Auto-sync enabled and prints the outcome.

Examples:

# Set a plain variable in the configured environment
envmanager set LOG_LEVEL=debug

# Set a secret in production
envmanager set STRIPE_KEY=sk_live_... --environment production --secret

# Several at once; the value may contain = and can be quoted
envmanager set API_URL="https://api.example.com" DEBUG=true

# Turn an existing secret back into a plain variable
envmanager set PORT=3000 --no-secret

# Set on a service
envmanager set WORKER_CONCURRENCY=4 --service worker

Output:

✔ Set STRIPE_KEY in production [secret]
  0 inserted, 1 updated

Values are split on the first =, so DATABASE_URL=postgres://u:p@host/db?sslmode=require works as expected. Matching surrounding quotes are removed. A secret can't have an empty value; a plain variable can. Naming conventions are checked exactly as in push.

service

Manage services — named subdivisions of a project such as api or worker that keep their own set of variables per environment.

service create

envmanager service create <name> [options]

Options:

OptionDescription
--org <name>Organization name (only needed if you belong to several)
-p, --project <id>Project ID, friendly ID or name (default: from config)
-d, --description <text>Optional description

The command is safe to run repeatedly: if the service already exists (names are matched case-insensitively) it reports that and exits successfully, so it can run unconditionally in CI. Only organization owners and admins can create services.

envmanager service create worker --description "Background jobs"
envmanager push --service worker

diff

Compare a local .env file with the variables stored in EnvManager. It only reports; it never changes anything.

envmanager diff [options]

Options:

OptionDescription
--org <name>Organization name (only needed if you belong to several)
-e, --environment <name>Environment name (default: from config or "development")
-p, --project <id>Project ID, friendly ID or name (default: from config)
-i, --input <file>Local file to compare (default: .env)
--service <name>Compare against a service: its variables plus the shared ones (default: service from config, or the whole environment)
--keys-onlyOnly show key names, not values
--tag <tags...>Only compare variables with these tags (untagged variables are always included)

Output:

+ 1 to add (local only):
  + NEW_VAR=value

- 2 remote only (not touched by push):
  - OLD_VAR
  - LEGACY_TOKEN [secret]
  push never deletes: these stay on the server until you remove them in the web app.

~ 1 modified:
  ~ API_URL

8 unchanged

How to read it:

  • to add (local only) — keys in your file that don't exist remotely. push will create them.
  • remote only (not touched by push) — keys that exist remotely but not in your file. push leaves them alone; it never deletes. Remove them in the web app if they are obsolete, or pull to get them locally.
  • modified — the value differs. push will overwrite the remote value with yours; pull does the opposite.

Secret values are never shown in diff output.

Services: a key can exist once as a shared variable and once per service. Without --service, diff compares every row and tags ambiguous keys with their scope, e.g. ~ DATABASE_URL (service: api), and prints a note suggesting --service. With --service api, the comparison covers exactly what pull --service api and run --service api receive: the service's own variables plus the shared ones.

list

List projects, environments, or variables.

envmanager list <type> [options]

Types:

TypeDescription
projectsList all accessible projects
environmentsList environments in a project
variablesList variables in an environment

Options:

OptionDescription
--org <name>Organization name (only needed if you belong to several)
-p, --project <id>Project ID (for environments/variables)
-e, --environment <name>Environment name (default: "development")
--service <name>Only list that service's variables (default: service from config, or every scope)
-v, --verboseShow IDs (and creation dates for variables)

Examples:

# List all projects
envmanager list projects

# List environments in a project
envmanager list environments --project abc123

# List variables (uses config if no project specified)
envmanager list variables

# Only the variables of one service
envmanager list variables --service api

# Verbose output with IDs
envmanager list projects --verbose
envmanager list variables --verbose

Output:

✔ Found 3 projects

  #1   my-app (Acme)
  #2   backend-api (Acme)
  #3   marketing-site (Acme)
✔ Found 5 variables (2 secrets)

  API_KEY [secret] (shared)
  DATABASE_URL [secret] (service: api)
  DATABASE_URL [secret] (service: worker)
  DEBUG (shared)
  PORT (service: api)

Values are never listed; use pull for that. Each variable shows its scope: (shared) for variables every service receives, or (service: name). A key can appear more than once when it is defined per service. With --service, only that service's own rows are shown — shared variables are visible without the flag.

config

Manage project configuration.

envmanager config <action> [options]

Actions:

ActionDescription
initCreate envmanager.json interactively
get <key>Get a config value
set <key> <value>Set a config value

Examples:

# Initialize configuration
envmanager config init

# Get current project
envmanager config get project_id

# Change environment
envmanager config set environment staging

debug

Collect diagnostic info for troubleshooting. Share the output with support when reporting issues.

envmanager debug

Output:

=== EnvManager CLI Debug Report ===
Timestamp: 2026-02-19T15:48:27.806Z
CLI Version: 0.1.5
Node: v22.14.0
Platform: darwin arm64

--- Config ---
Config file: /path/to/envmanager.json
  project_id: not set
  environment: not set

--- Authentication ---
Auth method: CLI session key (em_abc1234...)
API URL: default (production)

--- API Connection ---
Auth exchange: 120ms
getUser: 45ms
  User ID: abc-123...
  Email: user@example.com
Org query: 32ms
  Organizations (1):
    - My Org (owner) [abc12345...]

=== End Debug Report ===

API keys are partially redacted. No secrets are exposed.

Common Workflows

Initial Setup

# Login once
envmanager login

# Initialize project
envmanager init --project <id>

# Pull current variables
envmanager pull

Daily Development

# Check what's different
envmanager diff

# Pull latest changes
envmanager pull --force

# Or use real-time sync
envmanager dev

Updating Production

# Compare with production
envmanager diff --environment production

# Push changes (with review)
envmanager push --environment production

# Or dry-run first
envmanager push --environment production --dry-run

Get DevOps tips in your inbox

Security best practices and product updates. No spam.

No spam. Unsubscribe anytime.