The CLI has two ways to authenticate, and the rules for which one wins are simple - once you’ve seen them. This step gets you logged in, gets a long-lived API key minted for CI, and shows you how to juggle multiple workspaces without accidentally deploying to prod.
The two auth modes
| Mode | Use it for | Where it’s stored | Lifetime |
|---|---|---|---|
render login (CLI token) | Local development on your laptop | ~/.render/cli.yaml | Periodic expiry, re-login when prompted |
RENDER_API_KEY (env var) | CI/CD, scripts, AI tooling | The environment of the process | Never expires (rotate manually) |
These coexist. The CLI picks one based on a precedence rule, which you’ll cover after you get both working.
Log in locally
render loginThe CLI opens your browser to a Render-hosted page, you confirm, and a token gets written to ~/.render/cli.yaml. The next command prompts you to pick a default workspace:
$render workspace set? Select a workspace > acme-prod acme-staging personal$render workspaceActive workspace: acme-prod (tea-xxxxxxxxxxxxxxxx)
The selected workspace is saved to the same cli.yaml. Every subsequent command runs against it until you switch.
Mint an API key for scripting
For anything non-interactive - CI/CD, cron jobs, your runbook script - use an API key instead of a CLI token. Generate one from the Render Dashboard:
- Open Account Settings In the Render Dashboard, click your avatar → Account Settings → API Keys.
- Create a key Click Create API key, name it after where it’ll live (
gh-actions-deploy,runbook-laptop,cron-backups). - Copy the value once The key is shown once. Paste it somewhere safe (1Password, a CI secret) before you close the dialog.
- Scope it by workspace Each key belongs to a specific workspace. To deploy to a different workspace from CI, you’ll need a separate key.
Set it in your shell:
export RENDER_API_KEY="rnd_xxxxxxxxxxxxxxxxxxxxxxxx"render servicesFor CI, drop it into a repo secret (RENDER_API_KEY) and expose it as an env var on the job.
Precedence: API key wins
When both are set, the API key always takes precedence over the saved CLI token.
flowchart TD
start["render <command>"]
apikey{"RENDER_API_KEY set?"}
useapi["Use API key (env)"]
cfg{"~/.render/cli.yaml exists?"}
usecfg["Use CLI token (login)"]
prompt["Prompt: render login"]
start --> apikey
apikey -->|"yes"| useapi
apikey -->|"no"| cfg
cfg -->|"yes"| usecfg
cfg -->|"no"| prompt
This matters more than it looks. The trap is when you have an API key exported in your shell for a script you wrote last month, and weeks later you wonder why render services shows different services than the Render Dashboard.
The fix is one of:
unset RENDER_API_KEYrender servicesor:
env -u RENDER_API_KEY render servicesThe second form is non-destructive - it strips the variable just for that command, leaving your shell untouched.
Switch workspaces without thinking
Most teams have at least two: a production workspace and a staging or sandbox one. Two patterns keep them straight.
Pattern A: change the default
render workspace setrender workspaceworkspace set is interactive; it lists every workspace your token can see and stores your pick. Good for short sessions where you’re focused on one workspace.
Pattern B: per-command override with an env var
RENDER_API_KEY=$STAGING_KEY render servicesRENDER_API_KEY=$PROD_KEY render servicesBecause API keys are workspace-scoped, swapping the key swaps the workspace. This is the right pattern for scripts and aliases:
alias render-prod='RENDER_API_KEY=$RENDER_PROD_API_KEY render'alias render-stg='RENDER_API_KEY=$RENDER_STAGING_API_KEY render'Then render-prod services and render-stg services give you instant, unambiguous switches.
Inspect what you’ve got configured
When something doesn’t feel right, two commands give you the truth:
$render workspaceActive workspace: acme-staging (tea-xxxxxxxxxxxxxxxx)$render workspaces -o json | jq '.[] | {name, id}'{ "name": "acme-prod", "id": "tea-yyyyyyyyyyyyyyyy" } { "name": "acme-staging", "id": "tea-xxxxxxxxxxxxxxxx" }
The first tells you what’s active right now. The second tells you what you could switch to. Together they’re enough to diagnose every “wait, why am I seeing this service?” moment.
Config file at a glance
~/.render/cli.yaml is just YAML. You can read it; you usually shouldn’t edit it.
token: rnd_cli_xxxxxxxxxxxxxxxxxxxxworkspace: id: tea-xxxxxxxxxxxxxxxx name: acme-stagingoutput: interactive| Field | Set by | Notes |
|---|---|---|
token | render login | Short-lived CLI token; replaced on every login |
workspace.id / name | render workspace set | The active workspace |
output | --output flag or interactive picker | Default output format; can be interactive, json, yaml, text |
If you keep multiple Render accounts (personal vs work), point RENDER_CLI_CONFIG_PATH at a different file per account:
alias render-work='RENDER_CLI_CONFIG_PATH=$HOME/.render/work.yaml render'alias render-personal='RENDER_CLI_CONFIG_PATH=$HOME/.render/personal.yaml render'Each alias gets its own login state. No more “wait, I’m signed into the wrong account”.
What you learned
- `render login` for laptops; `RENDER_API_KEY` for everything non-interactive
- API keys never expire and take precedence over the saved CLI token - useful for scripts, but a gotcha when you forget you exported one
- Switch workspaces with `render workspace set` for sessions, or swap `RENDER_API_KEY` per-command for unambiguous scripted switches
- `render workspace` and `render workspaces -o json` are your two diagnostic commands when something feels off
- Multiple Render accounts? Point `RENDER_CLI_CONFIG_PATH` at a different config file per account and alias each one