Lesson 3 of 6 · about 20 minutes
How environment variables work
The win One variable, three values: your app shows a different name in Production, in Preview and on your laptop, and you can say why a changed value did not show up until you redeployed.
This lesson uses a harmless value on purpose. Get the mechanics right with something that cannot hurt you, and the real keys in Lessons 4 and 5 become routine.
First, recall
After the first deployment, what kind of deployment does pushing a non-production branch create?
A Preview deployment, at its own generated URL. (Lesson 2)
What did vercel link create, and what is in it?
A .vercel directory with the project and org configuration. It contains no secrets and is ignored by Git.
Three facts carry the whole topic
1. A variable is a name, a value, and a list of environments. The same name can hold a different value in Production, in Preview and in Development. That is how one codebase talks to a live database in one place and a scratch database in another.
2. A deployment keeps the values it was created with. Changing a value in the dashboard changes nothing that is already running. The new value arrives with the next deployment, so after a change you redeploy.
3. In Next.js, the name decides who can see the value. A name beginning NEXT_PUBLIC_ is copied into the JavaScript sent to every visitor, at build time. Every other name stays on the server.
Tested, and worth knowing “Stays on the server” protects the JavaScript bundle. It does not protect you from yourself. A test page built for this course printed a server-only variable in its JSX: the value was absent from every file under .next/static, and it was sitting in the page's HTML, because the server rendered it there. The rule that follows: read secrets only inside Route Handlers and other server code, and never put one in anything you return.
Where the values live on your laptop
Next.js reads a file called .env.local when you run npm run dev. You do not write that file by hand. vercel env pull downloads the project's Development values into it. create-next-app already ignores .env* in Git, so the file stays off GitHub.
Do it
Run these from the beachhead folder, on main.
-
Add one name with three values. The value is public by design, so passing it on the command line is fine here.
--no-sensitivekeeps it readable later.vercel env add NEXT_PUBLIC_APP_NAME production --value "Beachhead" --no-sensitive --yes vercel env add NEXT_PUBLIC_APP_NAME preview --value "Beachhead (preview)" --no-sensitive --yes vercel env add NEXT_PUBLIC_APP_NAME development --value "Beachhead (dev)" --yes -
Look at what you made.
vercel env lsThree rows, one per environment. The same list is in the dashboard under the project's Environment Variables page.
-
Pull the Development value down.
vercel env pullOpen
.env.localand findNEXT_PUBLIC_APP_NAME. Then rungit status: the file is not listed, because it is ignored. -
Use it. Replace the home page with one line that shows the name.
app/page.tsx
export default function Home() { return <h1>{process.env.NEXT_PUBLIC_APP_NAME ?? "unnamed"}</h1>; }Run
npm run devand openlocalhost:3000. It says Beachhead (dev). -
Ship it.
git add -A git commit -m "Show app name from environment" git pushWhen the deployment is ready, your production domain says Beachhead. Same code, different value.
-
Predict, then observe. Change the Production value:
vercel env update NEXT_PUBLIC_APP_NAME production --value "Beachhead v2" --yesBefore you reload the production page, say out loud what it will show.
Reload it. What happened, and why?
It still says Beachhead. The running deployment was built with the old value, and a
NEXT_PUBLIC_value is baked into the JavaScript at build time. -
Redeploy. In the dashboard open Deployments, find the latest production deployment, open its ⋯ menu and choose Redeploy. When it finishes, reload: Beachhead v2.
That last pair of steps is the most common Vercel confusion there is. You have now seen it happen under controlled conditions.
Check yourself
You change a variable's value in the dashboard. When does your live production site start using it?
Changes “only apply to new deployments.” Nothing running is touched until you deploy again. Source
In a Next.js app, which variable name would place its value inside JavaScript sent to browsers?
Only the exact prefix NEXT_PUBLIC_ triggers inlining. That also makes this name a mistake: an API key must never carry the prefix. Source
You run vercel env pull with no arguments. Which values does it write, and where?
The CLI's own help says the default file is .env.local and the default environment is development. Production values stay on Vercel unless you ask for them with --environment.
A component reads a server-only secret and renders it in its JSX. What happens?
Nothing stops you. The server has the value, renders it, and sends the HTML to the visitor. The missing prefix only keeps the value out of the browser's JavaScript bundle. This was tested on Next.js 16.3.8 for this course.
Read this Environment variables in the Vercel docs, then the short “Bundling Environment Variables for the Browser” section of the Next.js guide. The recipes are collected on the env var playbook.
Ask your teacher If a prediction in step 6 surprised you, ask about it in your Claude Code session before moving on. Lesson 4 depends on it.