How to Use Environment Variables in Vite the Right Way

How to Use Environment Variables in Vite the Right Way

Vite makes it easy to use environment variables, but there’s a right way to do it, especially if you’re building for production, deploying to platforms like Vercel, and integrating external services or APIs.

This guide breaks down how Vite handles env variables, how to load them correctly, and how to avoid the most common mistakes developers make when going from dev to prod.

1. File Naming: .env, .env.local, .env.production, etc.

Vite will automatically load env files based on the current mode. Here's how the files map:

  • .env — Loaded in all modes.
  • .env.development — Loaded in vite dev.
  • .env.production — Loaded in vite build.
  • .env.local — Local overrides (never commit these).

Want to use a custom mode? Run:

vite build --mode staging

This loads .env.staging and .env.

2. Prefix with VITE_ or It Won’t Work

Only variables prefixed with VITE_ are exposed to your frontend code.

# This works:
VITE_API_BASE_URL=https://api.mysite.com

# This will be undefined in the browser:
API_SECRET_KEY=supersecret

Use the VITE_ prefix for anything you want to access in your app, like:

const apiUrl = import.meta.env.VITE_API_BASE_URL;

3. Accessing Env Vars in Code

In Vite, environment variables are accessed through import.meta.env, not process.env:

console.log(import.meta.env.MODE); // 'development', 'production', etc.
console.log(import.meta.env.VITE_SITE_NAME);

Want to log everything?

console.log(import.meta.env);

4. Using loadEnv in vite.config.js

If you need to access env variables in your vite.config.js file (e.g., for dynamic config):

import { defineConfig, loadEnv } from 'vite';

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd());

  return {
    define: {
      __SITE_ID__: JSON.stringify(env.VITE_SITE_ID)
    }
  };
});

This loads the proper .env.[mode] file based on the build or dev command.

5. Avoid Hardcoding Production URLs

Don't do this:

const apiUrl = 'http://localhost:3000'; // bad for prod

Do this instead:

const apiUrl = import.meta.env.VITE_API_BASE_URL;

Then set the correct value in .env.production:

VITE_API_BASE_URL=https://api.mysite.com

6. Bonus: Use with Fetch, Axios, etc.

const res = await fetch(`${import.meta.env.VITE_API_BASE_URL}/user`, {
  method: 'GET'
});

You can also write a wrapper around fetch that takes care of the base URL.

7. Common Pitfalls

  • Forgetting VITE_ prefix → Not available in frontend
  • Using process.env → Will be undefined or empty in Vite
  • Missing .env.production → Deployed site fetches from wrong server
  • Expecting server.proxy to apply in prod → Doesn’t work post-build

TL;DR

  • ✅ Use .env, .env.local, .env.production, etc.
  • ✅ Prefix all frontend env vars with VITE_
  • ✅ Access them via import.meta.env
  • ✅ Use loadEnv() in vite.config.js when needed
  • ✅ Avoid hardcoded URLs in your app logic

With proper setup, Vite’s env system is clean, predictable, and production-ready, as long as you respect the rules.

Walter Guevara is a Computer Scientist, software engineer, startup founder and previous mentor for a coding bootcamp. He has been creating software for the past 20 years.

Community Comments

No comments posted yet

Code Your Own Classic Snake Game – The Right Way

Master the fundamentals of game development and JavaScript with a step-by-step guide that skips the fluff and gets straight to the real code.

Ad Unit

Current Poll

Help us and the community figure out what the latest trends in coding are.

Total Votes:
Q:
Submit

Add a comment