# How to Access and Use Vite Env Variables in vite.config.js for Multi-Environment Builds

> Learn to access and use Vite env variables in vite.config.js. Load env using the loadEnv function for multi-environment builds and conditional configurations.

- Repository: [Vite/vite](https://github.com/vitejs/vite)
- Tags: how-to-guide
- Published: 2026-02-20

---

**You can access Vite env variables inside [`vite.config.js`](https://github.com/vitejs/vite/blob/main/vite.config.js) by importing the `loadEnv` function from the `vite` package, which synchronously parses `.env*` files based on the current mode and returns an object containing environment variables that you can use to conditionally configure plugins, server settings, and build options.**

Managing different build configurations requires a flexible way to inject environment-specific values into your build pipeline. The vitejs/vite repository provides a built-in environment system that allows you to read variables from `.env` files directly within your configuration file using Node.js APIs. By leveraging `loadEnv` alongside `import.meta.env`, you can create distinct behaviors for development and production while keeping sensitive data out of client bundles.

## Understanding Vite's Two-Stage Environment System

Vite processes environment variables in two distinct stages, each serving a different purpose in the build lifecycle.

**Server-side (Config Loading):** During config evaluation, Vite exposes `loadEnv`, implemented in [[`packages/vite/src/node/env.ts`](https://github.com/vitejs/vite/blob/main/packages/vite/src/node/env.ts)](https://github.com/vitejs/vite/blob/main/packages/vite/src/node/env.ts). This function reads `.env`, `.env.[mode]`, and `.env.[mode].local` files, expands variable references, and returns a `Record<string, string>` object.

**Client-side (Runtime):** Variables prefixed with `VITE_` are statically injected into `import.meta.env` at build time. This object also includes three boolean flags: `import.meta.env.DEV`, `import.meta.env.PROD`, and the string `import.meta.env.MODE`.

Because [`vite.config.js`](https://github.com/vitejs/vite/blob/main/vite.config.js) executes in Node.js, you can access both `process.env` (raw Node environment) and the values returned by `loadEnv`. The latter is preferred when you need values from `.env` files to influence configuration logic.

## Loading Variables with loadEnv

The `loadEnv` function is the primary API for accessing Vite env variables inside your configuration file. According to the [JavaScript API documentation](https://github.com/vitejs/vite/blob/main/docs/guide/api-javascript.md#loadenv), it accepts three arguments:

```typescript
loadEnv(mode: string, cwd: string, prefix = 'VITE_')

```

- **mode**: The current Vite mode (`development`, `production`, or custom values passed via `--mode`)
- **cwd**: The working directory, typically `process.cwd()`
- **prefix**: A filter string; only keys starting with this prefix are returned. Defaults to `'VITE_'`. Pass an empty string to retrieve all variables.

Vite automatically loads `.env` files in the following order, as documented in [[`docs/guide/env-and-mode.md`](https://github.com/vitejs/vite/blob/main/docs/guide/env-and-mode.md)](https://github.com/vitejs/vite/blob/main/docs/guide/env-and-mode.md):

1. `.env` – loaded in all cases
2. `.env.local` – loaded in all cases, ignored by version control
3. `.env.[mode]` – loaded only for the specific mode
4. `.env.[mode].local` – loaded last, overriding previous values

## Accessing Vite Env Variables in vite.config.js

To use environment variables for build configuration, destructure `mode` from the config function parameter and pass it to `loadEnv`:

```javascript
// vite.config.js
import { defineConfig, loadEnv } from 'vite'

export default defineConfig(({ command, mode }) => {
  // Load only VITE_* variables by default
  const env = loadEnv(mode, process.cwd())
  
  // Access variables to configure the dev server
  const port = Number(env.VITE_DEV_PORT) || 3000
  
  return {
    server: {
      port: port,
    },
    define: {
      // Inject build-time constants
      __APP_VERSION__: JSON.stringify(env.VITE_APP_VERSION),
    },
  }
})

```

For variables that should never reach the client (such as private API keys used only during the build process), you can still use `process.env` directly. However, `loadEnv` is required to access values defined in `.env` files.

## Managing Development vs Production Builds

The `mode` parameter allows you to create divergent configurations for different environments without maintaining separate config files.

```javascript
// vite.config.js
import { defineConfig, loadEnv } from 'vite'
import compress from 'vite-plugin-compress'

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

  return {
    plugins: [
      // Only enable compression plugin in production
      isProd && compress(),
    ].filter(Boolean),
    
    build: {
      // Adjust output directory based on env variable
      outDir: env.VITE_BUILD_DIR || 'dist',
    },
  }
})

```

When running `vite` (dev server), `mode` defaults to `development`. When running `vite build`, it defaults to `production`. You can override this with the `--mode` flag:

```bash
vite build --mode staging

```

This command loads `.env.staging` and sets `mode` to `"staging"`, allowing you to test staging-specific variables locally.

## Exposing Variables to Client-Side Code

Only environment variables prefixed with `VITE_` are exposed to your application code via `import.meta.env`. This security measure prevents accidental leakage of sensitive credentials.

```typescript
// src/main.ts
if (import.meta.env.DEV) {
  console.log('Development mode active')
}

// Access the variable defined in .env as VITE_API_URL
fetch(`${import.meta.env.VITE_API_URL}/users`)

```

Attempting to access non-prefixed variables (e.g., `import.meta.env.SECRET_KEY`) returns `undefined` in the browser, even if they exist in your `.env` file.

## Accessing Non-Prefixed Variables for Build Logic

Sometimes you need to read variables that do not start with `VITE_` to control build behavior, but you do not want to expose them to the client. Pass an empty string as the third argument to `loadEnv` to retrieve all variables:

```javascript
// vite.config.js
import { defineConfig, loadEnv } from 'vite'
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig(({ mode }) => {
  // Load ALL env variables, not just VITE_*
  const raw = loadEnv(mode, process.cwd(), '')
  
  const shouldAnalyze = raw.ANALYZE === 'true'
  const baseUrl = raw.BASE_URL ?? '/'

  return {
    base: baseUrl,
    plugins: [
      // Conditional plugin based on non-VITE variable
      shouldAnalyze && visualizer(),
    ].filter(Boolean),
  }
})

```

Be cautious when using this approach. Variables loaded without the `VITE_` prefix are intended for Node.js consumption only and should not be passed to `define` or other options that inject values into the client bundle.

## Summary

- **Use `loadEnv(mode, process.cwd())`** in [`vite.config.js`](https://github.com/vitejs/vite/blob/main/vite.config.js) to synchronously read `.env*` files based on the current mode, as implemented in [`packages/vite/src/node/env.ts`](https://github.com/vitejs/vite/blob/main/packages/vite/src/node/env.ts).
- **Reference `env.VITE_*`** to access variables that will also be available in your client code via `import.meta.env`.
- **Filter by mode** (`development`, `production`, or custom) to conditionally enable plugins, adjust server settings, or modify build outputs.
- **Use an empty prefix** (`loadEnv(mode, process.cwd(), '')`) to access non-prefixed variables for Node-only build logic, keeping secrets out of the browser bundle.
- **Prefer `process.env`** only for CI/CD secrets that exist solely in the Node environment and are not defined in `.env` files.

## Frequently Asked Questions

### Why are my environment variables undefined in `import.meta.env`?

Vite only exposes environment variables prefixed with `VITE_` to client-side code to prevent accidental leakage of secrets. Ensure your variable names start with `VITE_` (e.g., `VITE_API_URL`). If you need to access non-prefixed variables, use `loadEnv` with an empty string prefix inside [`vite.config.js`](https://github.com/vitejs/vite/blob/main/vite.config.js), but do not inject these into the client bundle.

### Can I use `process.env` instead of `loadEnv` in my config file?

Yes, `process.env` is available in [`vite.config.js`](https://github.com/vitejs/vite/blob/main/vite.config.js) and contains the raw Node.js environment. However, `process.env` does not automatically load values from `.env` files. Use `loadEnv` when you need variables defined in `.env`, `.env.development`, or `.env.production` to affect your build configuration.

### How do I load all environment variables without the `VITE_` prefix?

Pass an empty string as the third argument to `loadEnv`: `loadEnv(mode, process.cwd(), '')`. This returns all variables regardless of prefix. Use this for build-time logic (like enabling analysis plugins), but never expose these variables to the client via the `define` option, as they may contain sensitive information.

### What is the difference between `mode` and `NODE_ENV`?

The `mode` parameter is Vite-specific and determines which `.env` files are loaded (e.g., `.env.production` when mode is `production`). While `NODE_ENV` is a Node.js convention, Vite uses `mode` to control both environment file loading and the `import.meta.env.DEV`/`PROD` flags. You can set a custom mode (like `staging`) using `--mode staging`, which is independent of `NODE_ENV`.