EthioDeploy
PricingDocsBlogAbout
Start free
VITE_*

Fix deploy errors · October 29, 2026

Vite env variables undefined in production: causes and fixes

By Brook Solomon, Founder, EthioDeploy

A Vite env variable is undefined in production when the build never saw it. Vite replaces every import.meta.env.VITE_ reference with a fixed value while vite build runs, so a variable added to your server afterwards changes nothing until you build again. The other common causes are a name without the VITE_ prefix and code that reads process.env in the browser.

Why is my Vite env variable undefined in production?

Because Vite reads it once, during the build. The Vite docs say import.meta.env constants are “defined as global variables during dev and statically replaced at build time.” The built JavaScript holds the literal value. If the variable was missing when vite build ran, the built code has nothing to read.

That is why an app can work on your laptop and break after deploy. Your laptop has a .env.local file. The machine that builds your app usually doesn't.

// src/api.ts, what you write
const apiUrl = import.meta.env.VITE_API_URL

// dist/assets/index-*.js, what ships after the build
const apiUrl = "https://api.example.com"

Quick checklist

What you seeCauseFix
Works locally, undefined after deployThe value lives in .env.local, which git ignores, so the build server never had itSet the variable in your host's settings, then rebuild
Undefined everywhere, even locallyThe name has no VITE_ prefixRename it to VITE_* and restart the dev server
process is not defined in the browser consoleBrowser code reads process.envRead import.meta.env instead
Old value still shows after you changed itThe built files still hold the old valueRedeploy so vite build runs again
Undefined inside vite.config.ts.env files aren't loaded into process.env while the config runsUse loadEnv
"3000" + 1 gives "30001"Every value is a stringConvert it with Number(), or compare to "true"

Does the variable name start with VITE_?

Only variables that start with VITE_ reach your client code. Everything else is left out on purpose, so a database password in the same .env file never lands in the browser. This is the example from the Vite docs:

# .env
VITE_SOME_KEY=123
DB_PASSWORD=foobar
console.log(import.meta.env.VITE_SOME_KEY) // "123"
console.log(import.meta.env.DB_PASSWORD) // undefined

Moving from Create React App? REACT_APP_ names are not exposed. Rename them, or add the old prefix with the envPrefix option, which takes a string or an array:

// vite.config.ts
export default defineConfig({
  envPrefix: ["VITE_", "REACT_APP_"],
})

Never set envPrefix to an empty string. That would expose every variable in the environment, and Vite throws an error if you try.

Was the variable set when vite build ran?

The machine that runs vite build needs the variable. Setting it later on the server that serves the files does nothing for VITE_ values. Three details decide whether the build sees it:

  • .env.local and .env.*.local are meant to stay out of git, so a CI runner or a hosting platform never sees them.
  • vite build runs in production mode by default, so it loads .env, .env.local, .env.production and .env.production.local. A .env.development file is ignored.
  • Variables already set in the environment win over every .env file. Setting VITE_API_URL in your host's settings works even if a committed .env has a different value.

With Docker, pass the value as a build argument. Setting it with docker run -e is too late, because the image already holds the built files.

FROM node:22 AS build
WORKDIR /app
COPY . .
ARG VITE_API_URL
ENV VITE_API_URL=$VITE_API_URL
RUN npm ci && npm run build
docker build --build-arg VITE_API_URL=https://api.example.com .

Are you reading process.env in browser code?

Read import.meta.env instead. process is a Node.js global, and a Vite app doesn't have it in the browser, so process.env.VITE_API_URL usually fails with ReferenceError: process is not defined. This one is common in code copied from Create React App or webpack projects, and in AI-generated code.

Why is the value undefined in vite.config?

Because Vite reads your .env files after it has loaded the config. The Vite docs say those files are “not automatically injected into process.env while your vite.config.* is running.” Load them yourself with loadEnv:

import { defineConfig, loadEnv } from 'vite'

export default defineConfig(({ mode }) => {
  // '' loads every variable, whatever its prefix
  const env = loadEnv(mode, process.cwd(), '')
  return {
    define: { __APP_ENV__: JSON.stringify(env.APP_ENV) },
  }
})

Why does my number or boolean act like a string?

Every value in import.meta.env is a string, including 123 and true. Convert it where you read it:

const port = Number(import.meta.env.VITE_PORT)
const debug = import.meta.env.VITE_DEBUG === "true"

How to fix it on EthioDeploy

  1. Open the project, go to Environment Variables and add the variable with its VITE_ name.
  2. Leave “Runtime only” off. Runtime-only variables are kept out of the build, so a VITE_ value marked that way is always undefined in the browser.
  3. Redeploy. A changed value takes effect on the next build.

Apps exported from Lovable and Bolt hit this often, because their Supabase keys sit in a .env file that isn't in the repo. See Deploy a Lovable app and Environment variables.

Questions

Can I change a Vite env variable without rebuilding?

No. The value is written into the built JavaScript, so a change needs a new vite build. If you need settings that change without a rebuild, serve them from your backend or from a config.json file the app fetches when it starts.

Is it safe to put an API key in a VITE_ variable?

No. VITE_ values are bundled into the JavaScript your visitors download, so anyone can read them. Keep secret keys on a server and call that server from the app. Public keys that are meant for the browser, like a Supabase publishable key, are fine.

Does vite build read .env.local?

Yes, .env.local is loaded in every mode. But it is normally listed in .gitignore, so it exists on your laptop and not on the build server. Set the same values in your host's environment settings.

Which .env file does vite build use?

vite build runs in production mode, so it loads .env, .env.local, .env.production and .env.production.local. Mode-specific files win over generic ones, and variables already set in the environment win over all of them.

Why is my env variable undefined in vite.config.ts?

Vite loads .env files after the config runs, so they are not in process.env yet. Call loadEnv(mode, process.cwd(), '') inside defineConfig to read them.

Sources

Checked on October 29, 2026:

  • Vite: Env variables and modes
  • Vite: envPrefix option
  • Vite: Using environment variables in config

Push a repo. Get a URL.

  • Environment variables on EthioDeploy
  • Deploy a Lovable app
  • Deploy a Bolt app
Start free

On this page

  • Why is my Vite env variable undefined in production?
  • Quick checklist
  • Does the variable name start with VITE_?
  • Was the variable set when vite build ran?
  • Are you reading process.env in browser code?
  • Why is the value undefined in vite.config?
  • Why does my number or boolean act like a string?
  • How to fix it on EthioDeploy
  • Questions
  • Sources

Topics

  • Fix deploy errors2
  • Hosting and pricing1
  • Building from Ethiopia1

Deploy guides

  • Deploy a Next.js app
  • Deploy a Django app
  • Deploy a FastAPI app
  • Deploy a Laravel app
  • Deploy a Lovable app
All guides →

Written by

BSBrook SolomonFounder, EthioDeploy

More in Fix deploy errors

  • 0.0.0.0:$PORT

    FIX DEPLOY ERRORS · OCT 29

    502 Bad Gateway after deploy: bind to 0.0.0.0 and $PORT

Product

  • Pricing
  • Documentation
  • AI coding agent
  • Agent mode docs
  • Domains
  • Hosting in Ethiopia

Deploy guides

  • Next.js
  • Node.js
  • Python
  • SvelteKit
  • Django
  • FastAPI
  • Flask
  • Express
  • Laravel
  • Go
  • Lovable
  • Bolt
  • Replit
  • v0
  • Google AI Studio
  • Base44
  • Firebase Studio
  • Claude Code & Cursor

Compare

  • EthioDeploy vs Heroku
  • EthioDeploy vs Vercel
  • EthioDeploy vs Render
  • EthioDeploy vs Railway
  • EthioDeploy vs Fly.io
  • EthioDeploy vs Netlify
  • Heroku alternatives
  • Vercel alternatives
  • Netlify alternatives
  • Render alternatives
  • Railway alternatives

Company

  • About
  • Blog
  • Support
  • Contact
  • Terms
  • Privacy

EthioDeploy: agentic first development and deployment, started in Ethiopia, built for developers everywhere.