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.
Last updated on: