← ./articles

Vite Env Variables Not Updating? Restart Dev Server and Check the Cache

Vite makes environment variables convenient through import.meta.env, but that convenience creates a predictable debugging trap: developers edit .env, save the file, and expect hot module replacement to update the running app.

It usually will not. Vite loads .env files when the dev server starts. Source files hot-reload. Env files are startup inputs.

Symptom: import.meta.env is undefined or stale

The usual failure looks like this:

console.log(import.meta.env.VITE_API_BASE_URL);

The value is undefined, or it still shows the old URL after editing .env.

First check the name:

VITE_API_BASE_URL=https://api.example.test

Only variables with the configured public prefix, VITE_ by default, are exposed to client code. A variable named API_BASE_URL can exist in the process environment and still be absent from import.meta.env.

Restart after .env changes

After changing .env, stop and restart the dev server:

Ctrl+C
npm run dev

Do this before changing application code. Vite's own documentation says .env files are loaded at startup, so stale values after editing .env are not automatically a code bug.

Split production and development env files

Use mode-specific files when a value should never enter production builds:

.env
.env.development
.env.production

Example:

# .env.development
VITE_DEBUG_TRIAL_STATE=active 5
VITE_FORCE_ONBOARDING=true
# .env.production
VITE_PUBLIC_SITE_URL=https://example.com

This reduces the need for defensive code that tries to remove dev-only values during production builds. The build mode controls which file is loaded.

Declare custom env variables for TypeScript

Add a vite-env.d.ts entry when TypeScript should know about your variables:

/// <reference types="vite/client" />

interface ImportMetaEnv {
  readonly VITE_API_BASE_URL: string;
  readonly VITE_DEBUG_TRIAL_STATE?: string;
  readonly VITE_FORCE_ONBOARDING?: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}

This catches typos such as VITE_API_BASEURL earlier.

Do not trust import.meta.env.DEV as your only safety guard

import.meta.env.DEV is useful, but it should not be the only thing preventing a dangerous debug path from leaking into production behavior.

Prefer explicit debug variables:

const debugTrialState = import.meta.env.VITE_DEBUG_TRIAL_STATE ?? "";

if (debugTrialState) {
  // dev-only simulation path
}

Then make production builds strip or reject that value:

// vite.config.ts
import { defineConfig } from "vite";

export default defineConfig(({ mode }) => ({
  define:
    mode === "production"
      ? { "import.meta.env.VITE_DEBUG_TRIAL_STATE": JSON.stringify("") }
      : {},
}));

For apps where debug flags could alter licensing, payments, auth, or customer data, fail the production build if the flag is set. Do not rely on convention.

Clear Vite cache when dev mode looks impossible

Rarely, Vite's cache can make a dev session behave as if it is in the wrong mode. The symptom is stronger than a stale env value: dev-only code does not run even though the server was started with the dev command.

Try clearing Vite caches:

rm -rf node_modules/.vite .vite
npm run dev

On PowerShell:

Remove-Item -Recurse node_modules\.vite, .vite -ErrorAction SilentlyContinue
npm run dev

Do this after the simpler checks: variable prefix, server restart, and mode-specific files.

Static HTML placeholders also need verification

Vite can replace %VITE_*% placeholders in HTML:

<a href="%VITE_CHECKOUT_URL%">Buy now</a>

Always inspect the built output:

npm run build
grep -R "%VITE_" dist

If a placeholder remains in dist, the variable was not available at build time.

Debugging checklist

Use this order:

  1. Confirm the variable starts with VITE_.
  2. Restart the dev server after editing .env.
  3. Check whether the value belongs in .env.development or .env.production.
  4. Add the variable to vite-env.d.ts.
  5. Inspect dist after build for unresolved placeholders.
  6. Clear .vite caches only after the simpler checks fail.

References

Summary

Most Vite env bugs are not mysterious. Env files are startup inputs, client-visible variables need the VITE_ prefix, and production safety should not depend on a single runtime flag. Restart first, type the variables, and verify the built output.