CLI Reference
Every envi command.
envi <command> [flags]
Every command that touches your account first checks for a stored session (envi auth), then talks to the API directly — the CLI never needs the web dashboard running.
Authentication
envi auth
Signs in. By default this is the browser device flow: it prints a code, opens your browser, and waits for you to approve it there.
envi auth
--emailstringSkip the browser and sign in with an emailed one-time code instead. Prompts for the code interactively.
--no-browserbooleanWith the device flow, print the approval URL instead of trying to open a browser — useful over SSH.
envi auth --email you@company.com
envi auth --key <key>
Signs in with a personal API key instead of the browser. Useful on a machine where opening a browser isn't practical, and in scripts.
envi auth --key envi_...
The key is traded for an ordinary session, which is what gets stored. The key itself is never written to disk.
envi logout
Revokes the current device's session.
envi logout
Project setup
envi init
Links the current directory to a project and environment, writing envi.toml. Interactive if run with no flags.
--projectstring--envstringenvi init --project acme-api --env production
envi project create <name>
envi project create acme-api
Environments
A project holds any number of environments. The CLI calls them origins, because from a working directory what matters is which one you are pointed at — the dashboard and the API call the same thing an environment.
envi origin list
Lists the current project's origins, marking the one this directory is linked to.
envi origin list
* development
production
envi origin switch <name>
Repoints envi.toml at another origin and pulls its secrets into .env. If .env holds changes you have not pushed, the switch is refused rather than discarding them.
--forceboolean.env changes instead of refusingenvi origin switch production
envi origin use is an accepted alias.
envi origin create <name>
Creates an origin under the current directory's project (from envi.toml). It does not switch to it.
--projectstringenvi.toml--productionbooleanenvi origin create staging
envi origin create production --production
envi env create <name> is an accepted alias, with the same flags.
Working with secrets
These three all operate on the origin linked by envi init in the current directory, unless you name another one.
envi pull
Writes the environment's current secrets to .env, at 0600 permissions.
envi pull
envi push [file] [origin <name>]
Sends a local env file up. With no arguments it pushes .env to the origin this directory is linked to.
envi push
Name a file to push something other than .env:
envi push .env.test
Add origin <name> to write to a different origin without switching to it. Because that changes an origin you are not looking at, it prints what will change and waits for a yes:
envi push .env.test origin production
--forcebooleanPush even though the remote has moved on since your last pull, overwriting it with your local file. It also answers the confirmation prompt, so a cross-origin push with --force runs unattended.
--yesbooleanAnswer the confirmation prompt, without forcing past a conflict.
--cleanbooleanDelete the file once the push succeeds, so a pull, edit and push cycle leaves nothing plaintext on disk. A failed push never deletes anything.
envi pull # write .env
# ...edit it...
envi push --clean # send it up and remove the file
Without --force, a remote that changed since your last pull is rejected rather than overwritten:
remote secrets have changed since your last pull; run envi pull to take them,
or envi push --force to overwrite them with your local file
A push adds and updates the keys in the file it sends. It does not delete keys the file leaves out — remove those from the dashboard.
envi diff
Compares local .env against remote without changing either side. Prints added, removed, and changed keys.
envi diff
envi run -- <command>
Runs a command with the origin's secrets in its environment, without writing a .env at all. This is the better default for most projects: the secrets live for as long as the process does and never touch the disk.
envi run -- npm start
envi run -- ./deploy.sh
Everything after -- is the command, passed through untouched, including its own flags:
envi run -- npm run dev -- --port 3000
--originstringRun against another origin for this one command. envi.toml is not changed.
--preserve-envbooleanKeep the value already in your environment when a name exists in both. By default the secret wins.
envi run --origin production -- ./migrate.sh
envi run exits with the status of the command it ran, not with one of Envi's own exit codes, so scripts wrapping a command in envi run see exactly what they would have seen without it. A command that cannot be found exits 127; one killed by a signal exits 128 plus the signal number. Envi's own failures — not signed in, no envi.toml, API unreachable — all happen before the command starts.
In CI or a container, set ENVI_TOKEN to a service token and envi run works with no envi.toml at all — the token names the environment. ENVI_PROJECT and ENVI_ENVIRONMENT say which to read when the credential isn't scoped to one. See Docker.
envi clean
Deletes the local .env once the server already holds exactly what it contains. Use it after a pull and push, when the file has done its job.
envi clean
It refuses when the file has anything the server does not, naming what would be lost:
.env has 1 change the server does not have (added SECRET).
Run envi push first, or envi clean --force to delete them.
--forcebooleanDelete anyway, for a file you know is stale or unwanted.
Takes a filename to clean something other than .env. Running it with nothing to delete is not an error, so it is safe in a script.
envi push --clean does both steps in one go.
envi copy
Puts this origin's secrets on your clipboard as .env text, for pasting into a platform that runs your code itself.
envi copy
Copied 7 secrets from acme-api · production to the clipboard
Paste them into your deployment platform's environment variables.
Vercel, Netlify, Render, Railway and Fly all parse KEY=VALUE lines pasted into their environment-variable screens in bulk, so a whole environment moves in one paste instead of a row at a time. The text is exactly what envi pull writes: keys sorted, values quoted where a bare one would not survive.
envi copy <key>
Name a secret to copy that one value, on its own. No KEY= in front of it, because a single secret is copied in order to be pasted into a field that wants only the value.
envi copy DATABASE_URL
Copied DATABASE_URL from acme-api · production
A key that does not exist is an error that lists the ones that do, so a misremembered name is corrected in one step.
envi copy --single
Shows the origin's keys and copies whichever you choose.
envi copy --single
Copy a secret from acme-api · production
❯ API_KEY
DATABASE_URL
DB_PASSWORD
PORT
↑↓ move · type to filter · enter copy · esc cancel
| Key | Does |
|---|---|
| ↑ ↓ | Move, wrapping at either end |
| Any character | Narrow the list |
| Backspace | Undo one character of the filter |
| ^U | Clear the filter |
| Return | Copy the selected value |
| Esc or ^C | Leave without copying |
Filtering matches in order rather than literally, so dburl finds DATABASE_URL. The list draws in place and rubs itself out on exit, leaving your scrollback as it was.
--single needs an interactive terminal. In a script, name the key instead: envi copy DATABASE_URL.
--originstringCopy another origin instead of the linked one.
--stdoutbooleanWrite the text to stdout instead of the clipboard, for piping it or for a machine with no clipboard. The status line goes to stderr, so envi copy --stdout > .env is clean.
envi copy --origin production
envi copy --stdout | pbcopy
With no envi.toml, the credential names the environment, the same way envi run does in a container.
What lands on your clipboard is plaintext, and it stays there until something else replaces it. Paste it where you meant to and move on. Don't leave it sitting, and don't paste it into a chat window or a terminal with history.
Where you control the process, prefer envi run or the Docker setup: nothing is copied, nothing is pasted, and rotating a secret doesn't mean visiting a second dashboard.
envi mod
Opens this origin's secrets in a full-screen editor. Edit them, press ^O to push, and nothing is ever written to disk — no .env to create, forget, or clean up afterwards.
envi mod
| Key | Does |
|---|---|
| ^O | Push the buffer back to Envi |
| ^X | Leave; asks first if you changed anything |
| ^K | Cut the current line |
| ^A / ^E | Start and end of line |
| Arrows | Move around |
The buffer is the same KEY=VALUE text envi pull writes, so what you edit here and what lands in a file are the same thing. Add a line to add a secret, delete one to remove it.
--originstringEdit another origin instead of the linked one.
Pushing uses the same conflict check as envi push. If someone else changed the environment while you were editing, the push is refused and the status bar says so, rather than overwriting their work.
envi mod needs an interactive terminal. In a script or a pipe it refuses and points at envi pull and envi push instead.
Collaboration
envi share <email>
Invites a collaborator. They receive an email with a link — see Invitations for what happens next, including for people who don't have an account yet.
--projectstring--envstring--permissionstringdefault: readread, write, or manageenvi share teammate@company.com --permission write
envi invite accept <token>
Accepts an invitation using the token from an invitation link. You must already be signed in as the invited address — normally you'd just click the link instead, which handles this for you.
envi invite accept <token>
Personal API keys
A key is your own credential, not a project's. It acts as you, across everything you can reach, up to the permission you give it. For a credential scoped to a single environment, use a service token instead.
envi key create --name <name>
--namestringrequiredlaptop or ci--permissionstringdefault: readread, write, or manage. A read key cannot change anything; a write key can change secrets but cannot hand out access or create credentials.--daysintdefault: 900 never expires.envi key create --name laptop --permission read
The key is printed once and never again, because only a hash of it is stored.
envi key list
Your keys, with what each may do, when it expires, and when it was last used.
envi key revoke <id>
Stops a key working. Any session started with it is signed out at the same time, so a leaked key stops being useful immediately rather than when its session happens to run out.
The permission on a key is a ceiling, not a grant. It never gives you access you don't already have, and the usual per-environment permissions still apply underneath it.
CI/CD
envi token create --name <name>
Mints a scoped service token for the current directory's environment.
--namestringrequired--permissionstringdefault: readread, write, or manage--ttlintdefault: 00 means no expiry.envi token create --name github-actions --permission read --ttl 2592000
Everything else
envi activity
Recent reads and writes across your organization.
--limitintdefault: 20envi activity --limit 50
envi version
Prints the installed version.
envi help
Shows the command list.
Exit codes
Scripts checking envi's exit status can distinguish failure kinds without parsing output:
| Code | Meaning |
|---|---|
| 0 | Success |
| 2 | Usage error — bad flags or arguments |
| 3 | Not authenticated |
| 4 | Forbidden — authenticated, but not permitted |
| 5 | Configuration error — e.g. not initialized, run envi init |
| 6 | API error |
Updating
envi update check
Reports whether a newer release exists, without changing anything.
envi update now
Installs it. The route depends on how Envi was installed: a script install replaces its own binary after verifying the checksum, and a package-manager install hands over to npm, bun, pnpm or yarn, whichever owns it. Overwriting the file directly would leave the package manager still reporting the old version.
--forcebooleanUpdate even from a development build, or when already current.

