Skip to content
varsafe
Esc
navigateopen⌘Jpreview
On this page

CLI Reference

Install and authenticate the varsafe CLI, resolve context, and master the run/export workflows — plus the generated command reference.

CLI v7.2.7
varsafe CLI
varsafe CLI

Installation

The CLI is a self-contained binary — it is not published on npm. Six artifacts are published: Linux x64 and arm64, each for glibc and musl, plus macOS x64 and arm64. The installer picks the right one by detecting your architecture and C library. Windows works via WSL.

curl -fsSL https://varsafe.dev/install.sh | bash

The installer downloads the binary to ~/.varsafe/bin and adds it to your shell’s PATH. Verify the install and explore the commands — no account needed:

# docs-test: offline
# Check the CLI is installed and explore its commands — no account needed.
set -euo pipefail

varsafe --version

varsafe --help

echo "OK:help"

To upgrade later, the binary updates itself:

varsafe update

Commands at a glance

The CLI has 14 flat commands — no nested subcommands:

Command Description
login Authenticate with varsafe
logout Revoke session and clear credentials
whoami Display current authenticated user
use Set default project and environment context
list List secrets for a project/environment (alias: ls)
get Print a single secret value to stdout
set Set a secret in an environment
unset Remove a secret from an environment
run Run a command with secrets as environment variables
export Export secrets to a file or stdout
status Show the credential, the current context, and what is in it
doctor Diagnose whether the CLI can securely store credentials
theme Choose the colour palette (auto, dark, light)
update Update the CLI to the latest version

Every command and flag is documented in the generated reference at the bottom of this page.


Authentication

There are two ways to authenticate: an interactive browser login for humans, and an API token for machines.

Browser login (default)

varsafe login

The CLI opens your browser and prints a short, human-readable confirmation code in the terminal. Approve the request in the browser — after checking the code matches — and the CLI completes automatically via a server push, falling back to polling if the streaming connection drops. Your password never passes through the terminal.

Browser login stores the credential in your operating system’s keychain. That makes it the wrong choice for CI: a headless runner has no keychain, so varsafe login fails there. Use a token instead.

API token (CI and automation)

API tokens are created in the dashboard under team settings. Three ways to supply one:

# The CLI picks the token up automatically — no login step at all
export VARSAFE_TOKEN="vsafe_example_ci_token"
varsafe run -- ./deploy.sh
# "-" reads the token from stdin — keeps it out of argv
secret-manager read varsafe-token | varsafe login -t -
# Interactive masked input — never lands in shell history
varsafe login -T

For pipelines, prefer the environment variable and skip login entirely — see CI/CD usage.

Session commands

varsafe whoami   # show the authenticated user and teams
varsafe logout   # revoke the session server-side and clear local credentials

Logout invalidates the session immediately — a stolen credentials file is useless afterward.


Environment variables

Variable Purpose
VARSAFE_API_TOKEN API token for non-interactive auth — the primary CI variable
VARSAFE_TOKEN Shorter alias for VARSAFE_API_TOKEN; also read by varsafe login -t
VARSAFE_API_URL Overrides the API base URL (default https://api.varsafe.dev) — for self-hosted or test stacks
VARSAFE_DEBUG Set to any value to append a troubleshooting log to ~/.varsafe/debug.log (capped at 5 MB). Writes to the file, not to your terminal
VARSAFE_NO_UPDATE_CHECK Presence disables the interactive “update available” prompt — any value counts, including 0 and false, as with NO_COLOR. Set it in CI so the prompt cannot hang an unattended run
VARSAFE_THEME auto, dark, or light — overrides the saved palette for one invocation without rewriting settings. An unrecognized value is ignored

Context

Commands that touch secrets need a project and environment. Resolution order:

  1. Flags-p/--project and -e/--env (or -i/--project-id in automation) always win
  2. Local .varsafe file — found by searching from the current directory up to the git root
  3. Global saved context — set via varsafe use
  4. Auto-selection when only one option exists; interactive prompt otherwise
# Set context — inside a git repo this writes a .varsafe file,
# elsewhere it saves globally
varsafe use -p my-api -e development

# View the current context
varsafe use

# Clear it
varsafe use --clear

This script removes a secret and exercises the context lifecycle:

# docs-test: local-stack
# Remove a secret and manage the saved context.
set -euo pipefail

# VARSAFE_TOKEN in the environment authenticates every command below; `varsafe
# login` is neither needed nor possible on a headless runner (no keychain).
varsafe use -p "$VARSAFE_PROJECT" -e development

printf %s 'true' | varsafe set TEMP_FLAG --stdin
varsafe unset TEMP_FLAG

# Context can be cleared at any time; commands then need -p/-e flags
varsafe use --clear
varsafe list -p "$VARSAFE_PROJECT" -e development

echo "OK:unset-and-context"

Inject secrets into a process

varsafe run is the core workflow: it fetches secrets over TLS and injects them as environment variables into the child process. Nothing is written to disk; when the process exits, the secrets are gone.

varsafe run -- npm run dev

The command after -- is executed argv-exact — no shell re-parsing, so quoting is preserved and arguments arrive in the child process exactly as you wrote them. Status messages (“Injecting 5 secrets”) go to stderr, so stdout stays clean for piping.

That also means shell syntax is not interpreted: ;, |, &&, $() and backticks reach your program as literal characters rather than being executed. This is deliberate — it stops a value such as a CI branch name from running as a command inside the process holding your secrets. When you do want a shell, ask for one explicitly with --shell, which takes a single command string:

varsafe run --shell 'bun run build && ./deploy.sh'

Prefer the argv form when you can. Reach for --shell only for pipes, &&, and redirection — and note that --shell 'setup && exec app' keeps your real process in the foreground, which matters for signal handling.

Shape what gets injected:

# Only secrets matching glob patterns (comma-separated)
varsafe run --include 'VITE_*,CRISP_*' -- bun run build

# Rename injected keys: each secret is exposed with MONITORING_ prepended
# (e.g. DATABASE_URL becomes MONITORING_DATABASE_URL). Keys that already start
# with the prefix are left unchanged.
varsafe run --prefix monitoring -- ./run-monitoring.sh

--include selects which secrets are injected; --prefix renames them. They compose.

Merge in an encrypted .env file — file values win over API values, and the flag can be repeated. Every file must be sealed to the environment the command resolves to, since that is the key it can ask for:

varsafe run --env-file .env --env-file .env.extra -- npm start

--env-file reads encrypted files only; a plaintext file is refused. To merge a plaintext .env, source it in the shell — inside the child, so its values still win over the injected secrets:

varsafe run --shell 'set -a; . ./.env.local; set +a; exec npm start'

The full version, including the child process assertion:

# docs-test: local-stack
# Inject secrets into a child process as environment variables — no file
# is ever written to disk.
set -euo pipefail

# VARSAFE_TOKEN in the environment authenticates every command below; `varsafe
# login` is neither needed nor possible on a headless runner (no keychain).
varsafe use -p "$VARSAFE_PROJECT" -e development

printf %s 'vsafe_example_run_inject_value' | varsafe set API_KEY --stdin

# The child process sees API_KEY; your shell never does.
varsafe run -- sh -c 'test -n "$API_KEY"'

# Only inject secrets matching a pattern
varsafe run --include 'API_*' -- sh -c 'test -n "$API_KEY"'

echo "OK:run-inject"

Read a single value

For piping one secret into another tool, varsafe get prints just the value:

# Use a secret inline without exposing it in your shell profile
psql "$(varsafe get DATABASE_URL)"

# Exact bytes, no trailing newline — for tools that are byte-sensitive.
# On Linux, /dev/shm keeps it in RAM; macOS has no /dev/shm, so use a
# path you control and remove it afterwards.
varsafe get SIGNING_KEY -n > ./key

# Structured output: {key, value, version, updatedAt}
varsafe get DATABASE_URL --json

Export secrets to a file

When a tool insists on a file, varsafe export writes one. The .env format is encrypted by default: the file starts with a #@varsafe/v2/ek_<id> header identifying the environment key, and each value is individually encrypted and bound to its variable name (varsafe:v2:...). Encrypted .env files are readable only by your team — safe to commit — and are decrypted on the fly by varsafe run --env-file.

Writing an encrypted file needs only the environment’s public key, so it works with an API token as well as interactively. Reading one back does not: decryption needs the private key, which only an interactive owner or admin can fetch. So a CI job can produce an encrypted .env, but it cannot consume one — see encrypted .env.

# Encrypted .env (default)
varsafe export -o .env

# Plaintext requires an explicit opt-in
varsafe export --plain -o .env

# Other formats: compose (alias: env), docker (alias: kubectl), json, yaml (alias: yml) —
# auto-detected from the output file extension, or forced with -f
varsafe export --plain -o secrets.json
varsafe export --plain -f yaml

# Write to RAM-backed tmpfs (/dev/shm) so the file never touches disk
varsafe export --plain --tmpfs -o app.env

The export flow, covering the encrypted default, --plain, and format variants:

# docs-test: local-stack
# docs-test-allow-plaintext
# Export secrets when a file is genuinely required. The default .env export
# is encrypted; --plain is an explicit opt-in.
set -euo pipefail

# VARSAFE_TOKEN in the environment authenticates every command below; `varsafe
# login` is neither needed nor possible on a headless runner (no keychain).
varsafe use -p "$VARSAFE_PROJECT" -e development

printf %s 'smtp.example.com' | varsafe set SMTP_HOST --stdin

workdir="$(mktemp -d)"
trap 'rm -rf "$workdir"' EXIT

# Encrypted .env (the default). Sealing reads the environment's PUBLIC key, which a
# token is allowed to do, so this works under token auth as well as interactively.
varsafe export -o "$workdir/.env"
grep -q '#@varsafe/v2/' "$workdir/.env"

# Plaintext requires an explicit flag
varsafe export --plain -o "$workdir/plain.env"
grep -q 'SMTP_HOST=' "$workdir/plain.env"

# Other formats: json, yaml, docker
varsafe export --plain -f json -o "$workdir/secrets.json"
varsafe export --plain -f yaml -o "$workdir/secrets.yaml"

echo "OK:export-formats"

CI/CD usage

For pipelines, set VARSAFE_API_TOKEN from your CI secret store — no varsafe login step is required:

name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install varsafe CLI
        run: curl -fsSL https://varsafe.dev/install.sh | bash

      - name: Deploy with secrets
        run: varsafe run -p my-api -e production -- ./deploy.sh
        env:
          VARSAFE_API_TOKEN: ${{ secrets.VARSAFE_API_TOKEN }}
deploy:
  stage: deploy
  script:
    - curl -fsSL https://varsafe.dev/install.sh | bash
    - varsafe run -p my-api -e production -- ./deploy.sh
  variables:
    VARSAFE_API_TOKEN: $VARSAFE_API_TOKEN

Exit codes

Code Meaning
0 Success
1 Authentication failed
2 Network error
3 Validation error
4 Resource not found
5 Permission denied
99 Internal error

varsafe run is an exception: once the child process starts, run exits with the child’s exit code, so wrappers and CI steps behave as if the command ran directly.


Uninstall

To remove varsafe from your system:

# Remove the binary and local data
rm -rf ~/.varsafe

Then remove the PATH entry from your shell configuration:

# Edit ~/.zshrc and remove the line:
# export PATH="$HOME/.varsafe/bin:$PATH"
# Edit ~/.bashrc and remove the line:
# export PATH="$HOME/.varsafe/bin:$PATH"
# Edit ~/.config/fish/config.fish and remove:
# fish_add_path ~/.varsafe/bin

If you used varsafe use in any project directories, you can also delete the .varsafe context files in those repositories.


Troubleshooting

Error messages, their causes, and the fix for each are in the troubleshooting guide — expired tokens, a stuck browser login, Not signed in, an empty varsafe list, Project is required in CI, secure-storage failures, and rate limits.

One case belongs here, because it happens before the CLI can report anything: varsafe: command not found right after installing. The installer adds ~/.varsafe/bin to your shell config, which an already-open shell has not read yet. Restart the terminal, or add it for the current session:

export PATH="$HOME/.varsafe/bin:$PATH"

If it is still missing, run the installer again and read its Detected platform: line — it names the artifact chosen for your OS, architecture and C library.


Command reference

Generated from the CLI’s own --help output — always matches the shipped binary.

varsafe login

Authenticate with varsafe

varsafe login [options]

Flag

Type

Description

--api-url <url>

value

API URL (defaults to $VARSAFE_API_URL, then the public API)

-t, --token [token]

optional

Authenticate with an API token. Omit the value for a masked prompt, or pass "-" to read it from stdin. An inline value is rejected — it would leak to shell history.

-T, --token-prompt

boolean

Alias for `--token` with no value (masked prompt)

-f, --force

boolean

Force re-authentication even if already logged in

-h, --help

boolean

display help for command

varsafe whoami

Show the credential this machine is using and what it may do

varsafe whoami [options]

Flag

Type

Description

--json

boolean

Output the credential description as JSON

-h, --help

boolean

display help for command

varsafe logout

Revoke this machine’s credential and clear it locally

varsafe logout [options]

Flag

Type

Description

-h, --help

boolean

display help for command

varsafe list

Alias: ls

List secrets for a project and environment

varsafe list|ls [options]

Flag

Type

Description

-p, --project <name>

value

Project name

-i, --project-id <id>

value

Project ID (for CI/automation)

-e, --env <environment>

value

Environment (e.g., development, staging, production)

-r, --reveal

boolean

Show actual secret values

--json

boolean

Output as JSON

--include <patterns>

value

Comma-separated glob patterns to filter keys (e.g., --include "VITE_*,*_URL") — same syntax as `varsafe run --include`

--source

boolean

With --reveal, show composed secrets as written instead of resolved

-h, --help

boolean

display help for command

varsafe run

Run a command with secrets as environment variables

varsafe run [options] <command...>

Flag

Type

Description

-p, --project <name>

value

Project name

-i, --project-id <id>

value

Project ID (for CI/automation)

-e, --env <environment>

value

Environment (e.g., development, staging, production)

--prefix <prefix>

value

Rename injected keys with PREFIX_ prepended — renames, does not filter (e.g., --prefix monitoring). Use --include to select keys

--include <patterns>

value

Comma-separated glob patterns to filter which secrets get injected (e.g., --include "VITE_*,CRISP_*")

--env-file <path>

value

Decrypt an encrypted .env file and merge it into the injected secrets (can be repeated). Only encrypted files are accepted — source a plaintext .env in your shell instead

--shell

boolean

Run a single command string through /bin/sh (enables pipes, &&, etc.): varsafe run --shell 'a && b'. On an interactive terminal, use exec for graceful shutdown, e.g. --shell 'setup && exec main'

-h, --help

boolean

display help for command

varsafe export

Export secrets to a file or stdout (env format encrypts by default, use –plain to disable)

varsafe export [options]

Flag

Type

Description

-p, --project <name>

value

Project name

-i, --project-id <id>

value

Project ID (for CI/automation)

-e, --env <environment>

value

Environment (e.g., development, staging, production)

-o, --output <file>

value

Write to file instead of stdout (format auto-detected from extension)

-f, --format <format>

value

Override serialization: compose (.env), docker, kubectl, json, yaml (default: compose)

--plain

boolean

Skip encryption and output plaintext values

--tmpfs

boolean

Write to /dev/shm/ (RAM-backed tmpfs)

-h, --help

boolean

display help for command

varsafe get

Print a single secret value to stdout (pipe-friendly)

varsafe get [options] <key>

Flag

Type

Description

-p, --project <name>

value

Project name

-i, --project-id <id>

value

Project ID (for CI/automation)

-e, --env <environment>

value

Environment (e.g., development, staging, production)

--json

boolean

Output {key, value, version, updatedAt} as JSON

--source

boolean

Print a composed secret as written instead of resolved

-n, --no-newline

boolean

Do not append a trailing newline (exact byte output for piping)

-h, --help

boolean

display help for command

varsafe set

Set a secret in an environment

varsafe set [options] <key>

Flag

Type

Description

-p, --project <name>

value

Project name

-i, --project-id <id>

value

Project ID (for CI/automation)

-e, --env <environment>

value

Environment (e.g., development, staging, production)

-s, --stdin

boolean

Read the value from stdin (e.g. printf %s "$SECRET" | varsafe set KEY --stdin)

--json

boolean

Output {key, version, project, environment} as JSON

-T, --prompt

boolean

Prompt for the value with masked input (default at a terminal; does not leak to shell history)

--from-env <name>

value

Read the value from an environment variable (for CI)

--from-file <path>

value

Read the value from a file (multi-line certs, private keys)

--chomp

boolean

Strip one trailing newline from the value (for echo-style producers)

--template <source>

value

Store a value composed from other secrets, e.g. 'postgres://${DB_PASS}@db'

-y, --yes

boolean

Skip the confirmation required in protected environments

-h, --help

boolean

display help for command

varsafe unset

Remove a secret from an environment

varsafe unset [options] <key>

Flag

Type

Description

-p, --project <name>

value

Project name

-i, --project-id <id>

value

Project ID (for CI/automation)

-e, --env <environment>

value

Environment (e.g., development, staging, production)

-y, --yes

boolean

Skip the confirmation required in protected environments

--json

boolean

Output {key, removed, project, environment} as JSON

--flatten

boolean

Keep dependent secrets working by copying this value into each of them

--cascade

boolean

Delete every secret composed from this one as well

-h, --help

boolean

display help for command

varsafe doctor

Diagnose whether the CLI can securely store credentials

varsafe doctor [options]

Flag

Type

Description

--addon-only

boolean

Only verify the native keyring addon loads (tolerate a missing OS backend)

--json

boolean

Emit the report as JSON

-h, --help

boolean

display help for command

varsafe status

Show the credential, the current context, and what is in it

varsafe status [options]

Flag

Type

Description

--json

boolean

Output the status as JSON

-h, --help

boolean

display help for command

varsafe theme

Choose the colour palette (auto, dark, light)

varsafe theme [options] [mode]

Flag

Type

Description

--json

boolean

Output the resolved theme as JSON (never prompts)

-h, --help

boolean

display help for command

varsafe update

Update varsafe CLI to the latest version

varsafe update [options]

Flag

Type

Description

-h, --help

boolean

display help for command

varsafe use

Set default project and environment for commands

varsafe use [options]

Flag

Type

Description

-p, --project <name>

value

Project name

-e, --env <environment>

value

Environment (e.g., development, staging, production)

--clear

boolean

Clear the current context

--json

boolean

Output the resulting context as JSON (never prompts)

-h, --help

boolean

display help for command