Vercel env vars — multi-target single entry (CLI limitation + REST API workaround)
Vercel env vars — multi-target single entry (CLI limitation + REST API workaround)
TL;DR
vercel env add NAME <target> (CLI v55) prima jedan target po
pozivu (production | preview | development). Za jedan Vercel env
entry koji pokriva više environmentala odjednom (tipa "Production,
Preview" u dashboardu) — koristi Vercel REST API
POST /v10/projects/{projectId}/env?teamId=... s target: [...] array
u payloadu. Alternativa (više env add poziva) proizvodi više odvojenih
entryja koji su funkcionalno identični ali dashboard-visually neuredni.
Kontekst
Kad primijeniti:
- Postavljaš isti env var (najčešće API DSN, public key, feature flag) na Production i Preview odjednom i želiš dashboard prikazati jedan red umjesto dva.
- Migriraš postojeći "duplicated" env (npr. 2 odvojena Prod + Preview entrya) u jedan konsolidirani entry.
- Automatiziraš setup env varsa iz skripte i želiš idempotent behavior.
Kad NE:
- Vrijednost je stvarno različita po environmentu (development vs. production API URL) — onda odvojeni entryji imaju smisla.
- Trebaš samo Development entry — direktan
vercel env add ... developmentje najkraći put, i tamo se automatski postavljaType: Non-sensitive(Vercel requirement da bivercel env pullmogao skinuti vrijednost u.env.localna disk).
Zašto CLI ne može
CLI v55 signature je vercel env add [name] [environment] [git-branch],
gdje je environment enum single value. Više puta pokušavano
vercel env add NAME production preview — CLI parsira preview kao
git-branch, ne kao drugi env target. Nema --environment repeated
flaga u v55 (možda u budućoj verziji).
Iz output-a stvarnog testa:
$ vercel env add NEXT_PUBLIC_SENTRY_DSN production
✓ Added
Environments Production
Type Sensitive
$ vercel env add NEXT_PUBLIC_SENTRY_DSN preview
✓ Added
Environments Preview
Type Sensitive
Rezultat: 2 odvojena rowa u vercel env ls. Runtime resolution je
identičan (Next.js proces vidi process.env.NEXT_PUBLIC_SENTRY_DSN s
istom vrijednosti bez obzira koji entry je "izvor"), ali dashboard je
loš UX i tim koji gleda audit misli da su duplikati.
REST API workaround
Endpoint (v10 stabilan 2026-07): POST https://api.vercel.com/v10/projects/{projectId}/env?teamId={teamId}
Payload:
{
"key": "NEXT_PUBLIC_SENTRY_DSN",
"value": "https://…@ingest.…/…",
"type": "encrypted",
"target": ["production", "preview"]
}
Bitni detalji:
type: "encrypted"= ekvivalent "Sensitive" u dashboardu. Ostalo:"plain"(Non-sensitive, tj. vrijednost vidljiva u dashboardu),"secret"(legacy Vercel Secrets — deprecated, ne koristiti).target: []može biti bilo koja kombinacijaproduction,preview,development. Za granularno "Preview samo na specifičnoj grani" postojigitBranchpolje.- Response 201 sadrži
createdobjekt sidnovog entrya (npr.7wRFVQDypKfqnGVS) — koristan za auditlog. - Response 200 s
failed[]ako entry sa istim key-em već postoji za target — moraš prvoDELETEpostojeći.
Runbook — potpuni ciklus (jedan entry preko Prod + Preview)
# 1. Extract IDs
PID=$(python3 -c "import json; print(json.load(open('.vercel/project.json'))['projectId'])")
TID=$(python3 -c "import json; print(json.load(open('.vercel/project.json'))['orgId'])")
# 2. Extract CLI auth token (Linux path)
TOKEN=$(python3 -c "import json; print(json.load(open('$HOME/.local/share/com.vercel.cli/auth.json'))['token'])")
# 3. Delete any pre-existing single-target entries
vercel env rm NAME production --yes 2>/dev/null || true
vercel env rm NAME preview --yes 2>/dev/null || true
# 4. Create consolidated entry via REST API
curl -sS -X POST "https://api.vercel.com/v10/projects/$PID/env?teamId=$TID" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"key\":\"NAME\",\"value\":\"$VALUE\",\"type\":\"encrypted\",\"target\":[\"production\",\"preview\"]}" \
-w "\nHTTP %{http_code}\n"
# 5. Verify
vercel env ls production | rg NAME
# expected: NAME Encrypted Production, Preview
Gotchas
orgIdu.vercel/project.jsonje stvarno TEAM ID. Nema zasebnogteamIdpolja; koristiorgIdu query stringu kaoteamId=....- Auth token 60 chars. Live token na Linux mašini je u
~/.local/share/com.vercel.cli/auth.json(macOS:~/Library/…, Windows:%APPDATA%\…). Ako je taj file 0 bajtova ili token expired →curlće vratiti 401. Fix:vercel logout && vercel login. jqnije uvijek instaliran. Fallback:python3 -c "import json; print(json.load(open('...'))['token'])". Node fallback:node -e "console.log(require('...').token)".- Redeploy nije potreban kad se vrijednost env-a ne mijenja
(samo se konsolidira broj entryja). Trenutni Ready deploy nastavlja
raditi normalno; sljedeći build pokupi novu strukturu. Ali ako se
vrijednost promijenila, moraš eksplicitno
vercel redeployili push commit — Vercel ne redeploya automatski na env change. vercel redeploy https://aliased-domain.comvisi na interaktivnom promptu jer očekuje specifičan deployment URL, ne alias. Fix: koristi URL izvercel ls(https://protos-xxxx.vercel.app) ili samovercel deploy --prodiz linkanog direktorija.--yesflag navercel env rmpreskače interaktivni potvrdni prompt. Bez njega u skripti CLI zamrzne čekajući stdin.- Non-sensitive vs Sensitive tip je automatski određen: ako je var
samo u Development, Vercel forsira Non-sensitive (readable za
vercel env pull); ako je i u Prod ili Preview, može biti Encrypted. API poziv može eksplicitno postavititype: "encrypted". - Prozor bez env vara između
rmiPOSTje ~2s. Nije problem ako nema aktivnog builda u tom trenu; runtime već pokrenutih deploya nije pogođen jer je vrijednost bake-ana pri buildu (zaNEXT_PUBLIC_*) ili resolveana iz snapshot-a env-a pri cold startu (za server env). Za ultra-sigurnost: odgodi cleanup do window-a bez pushova.
Vidi također
memory/sessions/2026-07-20-12-sentry-env-wireup-consolidation.md— konkretna primjena (Sentry DSN)- Vercel REST API — Environment Variables: https://vercel.com/docs/rest-api/reference/endpoints/projects/create-one-or-more-environment-variables
- Vercel CLI reference —
vercel env: https://vercel.com/docs/cli/env