Free SKILL.md scraped from GitHub. Clone the repo or copy the file directly into your Claude Code skills directory.
npx versuz@latest install vivekkarmarkar-claude-code-os-plugins-vercel-0-32-6-skills-env-varsgit clone https://github.com/VivekKarmarkar/claude-code-os.gitcp claude-code-os/SKILL.MD ~/.claude/skills/vivekkarmarkar-claude-code-os-plugins-vercel-0-32-6-skills-env-vars/SKILL.md---
name: env-vars
description: Vercel environment variable expert guidance. Use when working with .env files, vercel env commands, OIDC tokens, or managing environment-specific configuration.
metadata:
priority: 7
docs:
- "https://vercel.com/docs/environment-variables"
sitemap: "https://vercel.com/sitemap/docs.xml"
pathPatterns:
- '.env'
- '.env.*'
- '.env.local'
- '.env.production'
- '.env.development'
- '.env.test'
- '.env.production.local'
- '.env.development.local'
- '.env.test.local'
- '.env.example'
bashPatterns:
- '\bvercel\s+env\s+pull\b'
- '\bvercel\s+env\s+add\b'
- '\bvercel\s+env\s+rm\b'
- '\bvercel\s+env\s+ls\b'
chainTo:
-
pattern: '\b(OPENAI_API_KEY|ANTHROPIC_API_KEY|GOOGLE_API_KEY)\b'
targetSkill: ai-gateway
message: 'Direct provider API key detected — loading AI Gateway guidance for OIDC auth (no manual keys needed on Vercel).'
retrieval:
aliases:
- environment variables
- env file
- secrets
- config vars
intents:
- set env var
- manage secrets
- pull env vars
- configure environment
entities:
- .env
- vercel env
- OIDC
- environment variable
---
# Vercel Environment Variables
You are an expert in Vercel environment variable management — `.env` file conventions, the `vercel env` CLI, OIDC token lifecycle, and environment-specific configuration.
## .env File Hierarchy
Vercel and Next.js load environment variables in a specific order. Later files override earlier ones:
| File | Purpose | Git-tracked? |
|------|---------|-------------|
| `.env` | Default values for all environments | Yes |
| `.env.local` | Local overrides and secrets | **No** (gitignored) |
| `.env.development` | Development-specific defaults | Yes |
| `.env.development.local` | Local dev overrides | **No** |
| `.env.production` | Production-specific defaults | Yes |
| `.env.production.local` | Local prod overrides | **No** |
| `.env.test` | Test-specific defaults | Yes |
| `.env.test.local` | Local test overrides | **No** |
### Load Order (Next.js)
1. `.env` (lowest priority)
2. `.env.[environment]` (development, production, or test)
3. `.env.local` (skipped in test environment)
4. `.env.[environment].local` (highest priority, skipped in test)
### Critical Rules
- **Never commit secrets** to `.env`, `.env.development`, or `.env.production` — use `.local` variants or Vercel environment variables
- `.env.local` is always gitignored by Next.js — this is where `vercel env pull` writes secrets
- Variables prefixed with `NEXT_PUBLIC_` are exposed to the browser bundle — never put secrets in `NEXT_PUBLIC_` vars
- All other variables are server-only (API routes, Server Components, middleware)
## vercel env CLI
### Pull Environment Variables
```bash
# 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
```
### Add Environment Variables
```bash
# Interactive — prompts for value and environments
vercel env add MY_SECRET
# Non-interactive
echo "secret-value" | vercel env add MY_SECRET production
# Add to multiple environments
echo "secret-value" | vercel env add MY_SECRET production preview development
# Add a sensitive variable (encrypted, not shown in logs)
vercel env add MY_SECRET --sensitive
```
### List Environment Variables
```bash
# List all environment variables
vercel env ls
# Filter by environment
vercel env ls production
```
### Remove Environment Variables
```bash
# Remove from specific environment
vercel env rm MY_SECRET production
# Remove from all environments
vercel env rm MY_SECRET
```
## Bootstrap Flow (Fresh Clone / New Machine)
Use this sequence when setting up a project from scratch:
```bash
# 1) Link first so pulls target the correct Vercel project
vercel link --yes --project <name-or-id> --scope <team>
# 2) Pull env vars into .env.local
vercel env pull .env.local --yes
# 3) Verify required keys from .env.example exist in .env.local
while IFS='=' read -r key _; do
[[ -z "$key" || "$key" == \#* ]] && continue
grep -q "^${key}=" .env.local || echo "Missing in .env.local: $key"
done < .env.example
```
### Temporary Path: Run With Vercel Envs Without Writing a File
If you need Vercel environment variables immediately but do not want to write `.env.local` yet:
```bash
vercel env run -- npm run dev
```
This is useful for quick validation during bootstrap, but still pull `.env.local` for a normal local workflow.
### Re-pull After Secret or Provisioning Changes
After creating/updating secrets (`vercel env add`, dashboard changes) or provisioning integrations that add env vars (for example Neon/Upstash), re-run:
```bash
vercel env pull .env.local --yes
```
## OIDC Token Lifecycle
Vercel uses **OIDC (OpenID Connect)** tokens for secure, keyless authentication between your app and Vercel services (AI Gateway, storage, etc.).
### How It Works
1. **On Vercel deployments**: `VERCEL_OIDC_TOKEN` is automatically injected as a short-lived JWT and auto-refreshed — zero configuration needed
2. **Local development**: `vercel env pull .env.local` provisions a `VERCEL_OIDC_TOKEN` valid for ~12 hours
3. **Token expiry**: When the local OIDC token expires, re-run `vercel env pull .env.local --yes` to get a fresh one. Consider re-pulling at the start of each dev session to avoid mid-session auth failures
### Common OIDC Patterns
```ts
// The @vercel/oidc package reads VERCEL_OIDC_TOKEN automatically
import { getVercelOidcToken } from '@vercel/oidc'
// AI Gateway uses OIDC by default — no manual token handling needed
import { gateway } from 'ai'
const result = await generateText({
model: gateway('openai/gpt-5.2'),
prompt: 'Hello',
})
```
### Troubleshooting OIDC
| Symptom | Cause | Fix |
|---------|-------|-----|
| `VERCEL_OIDC_TOKEN` missing locally | Haven't pulled env vars | `vercel env pull .env.local` |
| Auth errors after ~12h locally | Token expired | `vercel env pull .env.local --yes` |
| Works on Vercel, fails locally | Token not in `.env.local` | `vercel env pull .env.local` |
| `AI_GATEWAY_API_KEY` vs OIDC | Both set, key takes priority | Remove `AI_GATEWAY_API_KEY` to use OIDC |
## 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` |
| 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** — only `vercel.app` production 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:
```bash
# Add a variable only for the "staging" branch
echo "staging-value" | vercel env add DATABASE_URL preview --git-branch=staging
```
## 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:
```bash
# 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).
### 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:
```bash
# 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
```
## Best Practices
1. **Use `vercel env pull` as part of your setup workflow** — document it in your README
2. **Never hardcode secrets** — always use environment variables
3. **Scope narrowly** — don't give preview deployments production database access
4. **Rotate OIDC tokens regularly in local dev** — re-pull when you see auth errors
5. **Use `.env.example`** — commit a template with empty values so teammates know which vars are needed
6. **Prefix client-side vars with `NEXT_PUBLIC_`** — and never put secrets in them
7. **Keep custom vars in `.env.development.local`** — protects them from `vercel env pull` overwrites
## Official Documentation
- [Environment Variables](https://vercel.com/docs/environment-variables)
- [Vercel CLI: env](https://vercel.com/docs/cli/env)
- [Next.js Environment Variables](https://nextjs.org/docs/app/building-your-application/configuring/environment-variables)