env

Manage Vercel environment variables. Commands include list, pull, add, remove, and diff. Use to sync environment variables between Vercel and your local development environment.

SKILL.md

GitHub

Vercel Environment Variables

Manage environment variables for the current Vercel project with safety rails to prevent secret leakage.

🔒 Never-Echo-Secrets Rule: Environment variable values must never appear in command output, summaries, or conversation text. Only show variable names, environments, and metadata (created date, type). This rule applies to all subcommands.

Preflight

  1. CLI available? — Confirm vercel is on PATH.
    • If missing: npm i -g vercel (or pnpm add -g vercel / bun add -g vercel).
  2. Project linked? — Check for .vercel/project.json in the current directory or nearest parent.
    • If not found: run vercel link interactively, then re-run /env.
  3. Detect environment files — Check for .env, .env.local, .env.production.local, .env.development.local in the project root. Note which exist for the diff subcommand.

Plan

Based on "$ARGUMENTS", determine the action:

Argument Action Destructive?
list / ls / (none) List env var names per environment No
pull Download env vars to local .env.local No (overwrites local file)
add <NAME> Add a new env var Yes (if production)
rm <NAME> / remove <NAME> Remove an env var Yes
diff Compare local vs Vercel key names No

For any operation that mutates production environment variables (add or rm targeting production):

⚠️ Production environment mutation requested. This will change environment variables on your live production deployment. Ask the user for explicit confirmation before proceeding. Do not mutate production env vars without a clear "yes."

Commands

"list" or "ls" or no arguments

<!-- Sourced from env-vars skill: vercel env CLI > List Environment Variables -->
# List all environment variables
vercel env ls

# Filter by environment
vercel env ls production

Present results as a table of variable names only grouped by environment. Never print values.

Name Production Preview Development
DATABASE_URL ✓ ✓ ✓
API_KEY ✓ ✓ —

"pull"

<!-- Sourced from env-vars skill: vercel env CLI > Pull Environment Variables -->
# Pull all env vars for the current environment into .env.local
vercel env pull .env.local

# Pull for a specific environment
vercel env pull .env.local --environment=production
vercel env pull .env.local --environment=preview
vercel env pull .env.local --environment=development

# Overwrite existing file without prompting
vercel env pull .env.local --yes

# Pull to a custom file
vercel env pull .env.production.local --environment=production

After pulling, remind the user:

Ensure .env*.local is in your .gitignore to avoid committing secrets.

"add <NAME>"

  1. Ask the user which environments to target: production, preview, development (can select multiple).
  2. If production is selected, require explicit confirmation (see Plan section).
  3. Run the add command:
<!-- Sourced from env-vars skill: vercel env CLI > Add Environment Variables -->

Every variable has a type:

Type After saving Use for
Secret Hidden in the dashboard and vercel env ls; can be replaced, never read back. Production and Preview Secrets are not returned by vercel env pull. Passwords, API keys, tokens, database URLs
Config Readable by members with access Non-sensitive values you need to read later

Deployments receive both types at build time and runtime. Secret and Config replaced the Sensitive toggle; existing Sensitive variables are Secrets.

# Interactive — prompts for value, environments, and type
vercel env add MY_SECRET

# Non-interactive: read the value from a file so it never lands in shell
# history or process arguments (echo "value" | ... and --value do both)
vercel env add MY_SECRET production < ./secret.txt

# Add to production and preview in one command
vercel env add MY_SECRET production,preview < ./secret.txt

# Set the type explicitly
vercel env add MY_SECRET production --type secret < ./secret.txt
vercel env add SITE_REGION production --type config < ./region.txt

# Add development in its own command; development-only adds default to Config
vercel env add MY_SECRET development < ./dev-secret.txt

# Update an existing value
vercel env update MY_SECRET production < ./secret.txt
  • Defaults: a non-interactive add to production, preview, or a custom environment is stored as Secret.
  • Public prefixes are always Config: variables such as NEXT_PUBLIC_* or VITE_* are exposed to browsers, so the CLI refuses --type secret for them. Keep a private value under a name without the prefix.
  • Flags: --type config|secret needs Vercel CLI 59.6 or later. Older CLIs use --visibility, now a deprecated alias of --type. --sensitive (Secret) and --no-sensitive (Config) still work in every version.
  • Team policy: Separate Production Secret Values requires a Production Secret to differ from the Preview, Development, and custom environment values of the same key. Under it, create separate Production and non-Production values instead of adding one value to all targets. It replaces the deprecated Enforce Sensitive Environment Variables policy.

The CLI will prompt for the value interactively — do not pass the value as a CLI argument or echo it.

"rm <NAME>" or "remove <NAME>"

  1. If the variable exists in production, require explicit confirmation.
  2. Run the remove command:
<!-- Sourced from env-vars skill: vercel env CLI > Remove Environment Variables -->
# Remove from specific environment
vercel env rm MY_SECRET production

# Remove from all environments
vercel env rm MY_SECRET

Confirm the target environment(s) with the user before executing.

"diff"

Compare local environment file key names against Vercel-configured key names. Only compare names — never read or display values.

  1. Read local env file keys (from .env.local or .env — whichever exists):
grep -v '^#' .env.local | grep '=' | cut -d'=' -f1 | sort
  1. Fetch Vercel env var names:
vercel env ls

Parse the output to extract variable names for the target environment (default: development).

  1. Present the diff:
## Env Diff — Local vs Vercel (development)

### In local but NOT on Vercel:
- EXTRA_LOCAL_VAR
- DEBUG_MODE

### On Vercel but NOT in local:
- ANALYTICS_KEY
- SENTRY_DSN

### In both:
- DATABASE_URL
- API_KEY
- NEXT_PUBLIC_APP_URL

If all keys match, report: "Local and Vercel environment keys are in sync."

Environment-Specific Configuration Reference

<!-- Sourced from env-vars skill: Environment-Specific Configuration -->

Vercel Dashboard vs .env Files

Use Case Where to Set
Secrets (API keys, tokens) Vercel Dashboard (https://vercel.com/{team}/{project}/settings/environment-variables) or vercel env add, as type Secret
Public config (site URL, feature flags) .env or .env.[environment] files
Local-only overrides .env.local
CI/CD secrets Vercel Dashboard (https://vercel.com/{team}/{project}/settings/environment-variables) with environment scoping

Environment Scoping on Vercel

Variables set in the Vercel Dashboard at https://vercel.com/{team}/{project}/settings/environment-variables can be scoped to:

  • Production — production domain deployments
  • Preview — branch/PR deployments
  • Development — vercel dev and vercel env pull

A variable can be assigned to one, two, or all three environments.

Git Branch Overrides

Preview environment variables can be scoped to specific Git branches:

# Add a variable only for the "staging" branch
vercel env add DATABASE_URL preview --git-branch=staging < ./staging-database-url.txt

Common Gotchas

<!-- Sourced from env-vars skill: Gotchas -->

vercel env pull Overwrites Custom Variables

vercel env pull .env.local replaces the entire file — any manually added variables (custom secrets, local overrides, debug flags) are lost. Always back up or re-add custom vars after pulling:

# Save custom vars before pulling
grep -v '^#' .env.local | grep -v '^VERCEL_\|^POSTGRES_\|^NEXT_PUBLIC_' > .env.custom.bak
vercel env pull .env.local --yes
cat .env.custom.bak >> .env.local  # Re-append custom vars

Or maintain custom vars in a separate .env.development.local file (loaded after .env.local by Next.js).

Pulled Files Omit Production and Preview Secrets

vercel env pull --environment=production (or preview) does not write Secret values, so a pulled file cannot reproduce production credentials. Keep separate Development values for local work instead of trying to copy production Secrets onto a machine.

Scripts Don't Auto-Load .env.local

Only Next.js auto-loads .env.local. Standalone scripts (drizzle-kit, tsx, custom Node scripts) need explicit loading:

# Use dotenv-cli
npm install -D dotenv-cli
npx dotenv -e .env.local -- npx drizzle-kit push
npx dotenv -e .env.local -- npx tsx scripts/seed.ts

# Or source manually
source <(grep -v '^#' .env.local | sed 's/^/export /') && node scripts/migrate.js

Verification

After any mutation (add or rm), verify the change took effect:

vercel env ls

Re-list environment variables and confirm:

  • For add: the new variable name appears in the expected environment(s).
  • For rm: the variable name no longer appears in the target environment(s).

If verification fails (variable still present after remove, or missing after add), report the discrepancy and suggest retrying.

Summary

Present a structured result block:

## Env Result
- **Action**: list | pull | add | remove | diff
- **Status**: success | failed
- **Variable**: <NAME> (for add/remove)
- **Environments**: production, preview, development (as applicable)
- **Details**: <key outcome>

For diff, include counts:

- **Local only**: N keys
- **Vercel only**: N keys
- **Shared**: N keys

Next Steps

Based on the action performed:

  • After list → "Run /env pull to sync to local, or /env diff to compare local vs Vercel."
  • After pull → "Restart your dev server to pick up the new variables. Run /env diff to verify sync."
  • After add → "Run /deploy to make the new variable available in your next deployment. For production, the variable is available immediately on the next request."
  • After remove → "The variable is removed. If your app depends on it, update your code or add a replacement. Consider redeploying with /deploy."
  • After diff → "Add missing variables with /env add <NAME>, or pull from Vercel with /env pull to sync."