# How to Use Vite Env Variables in React: A Complete Guide to import.meta.env

> Learn to use Vite env variables in React with import.meta.env. Discover the VITE prefix and static replacement for efficient client-side variable management.

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

---

**Vite exposes environment variables through `import.meta.env` rather than `process.env`, requiring the `VITE_` prefix for client-side variables and performing static replacement at build time for optimal performance.**

Managing configuration across development and production environments is essential for modern React applications. When working with **vite env variables**, understanding Vite's unique approach to environment handling—implemented in the `vitejs/vite` repository—is crucial for secure and efficient code. Unlike Create React App or Node.js environments, Vite uses a compile-time replacement strategy that eliminates runtime overhead while protecting sensitive data.

## How Vite Env Variables Work Under the Hood

Vite does not inject a `process.env` object into the client bundle. Instead, the framework reads `.env*` files on the server side, filters variables by a configurable prefix, and statically replaces references to `import.meta.env` with actual values during the build process.

The core implementation resides in [`packages/vite/src/node/plugins/define.ts`](https://github.com/vitejs/vite/blob/main/packages/vite/src/node/plugins/define.ts), where the **define** plugin handles the replacement logic and respects the `envPrefix` configuration. During development, `import.meta.env` is injected as a real object for debugging purposes, while in production, each usage is compiled away to a literal string. TypeScript definitions in [`packages/vite/client.d.ts`](https://github.com/vitejs/vite/blob/main/packages/vite/client.d.ts) provide full IDE support and type safety for these variables.

## Setting Up Vite Env Variables in React

### Creating .env Files

Vite automatically loads environment files from the project root following a specific priority order: `.env`, `.env.local`, `.env.[mode]`, and `.env.[mode].local`. The `loadEnv` implementation merges these files, with mode-specific local files taking highest precedence.

Create a `.env` file in your project root:

```text

# .env (root of the project)

VITE_API_URL=https://api.example.com
VITE_APP_TITLE=My Vite React App

# This will NOT be exposed to the client

SECRET_TOKEN=super-secret

```

**Important:** After adding or modifying variables, restart the Vite dev server (`npm run dev`) to reload the environment files.

### The VITE_ Prefix Requirement

By default, Vite only exposes environment variables that begin with `VITE_` to the client-side code. This security measure prevents accidental leakage of database credentials, API keys, or other secrets to the browser. Variables without this prefix are available in Node.js contexts (such as [`vite.config.ts`](https://github.com/vitejs/vite/blob/main/vite.config.ts)) but are stripped from the client bundle.

## Accessing Vite Env Variables in React Components

React components access environment variables through the global `import.meta.env` object. This works in both JavaScript and TypeScript files without additional polyfills.

```tsx
// src/App.tsx
import React from 'react';

export default function App() {
  // The value is a string at runtime (dev) or a literal at build time
  const apiUrl = import.meta.env.VITE_API_URL;
  const title = import.meta.env.VITE_APP_TITLE;

  return (
    <div>
      <h1>{title}</h1>
      <p>API endpoint: {apiUrl}</p>
    </div>
  );
}

```

TypeScript users benefit from automatic type definitions provided in [`packages/vite/client.d.ts`](https://github.com/vitejs/vite/blob/main/packages/vite/client.d.ts), which declares the `ImportMetaEnv` interface. This enables autocomplete and compile-time checking for environment variable names.

## Customizing the Env Prefix

If `VITE_` does not suit your naming conventions, you can configure a custom prefix via the `envPrefix` option in [`vite.config.ts`](https://github.com/vitejs/vite/blob/main/vite.config.ts). This configuration is documented in [`docs/config/shared-options.md`](https://github.com/vitejs/vite/blob/main/docs/config/shared-options.md).

```ts
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  // expose variables that start with APP_ instead of VITE_
  envPrefix: 'APP_',
});

```

With this configuration, a variable named `APP_FEATURE_FLAG=true` in your `.env` file becomes accessible via `import.meta.env.APP_FEATURE_FLAG`. You can only specify one prefix at a time, and it must not be empty to prevent accidental exposure of all environment variables.

## Using Env Variables Outside Components

Environment variables work identically in utility modules, API clients, or any other JavaScript/TypeScript file processed by Vite. The static replacement occurs across the entire source tree.

```ts
// src/utils/api.ts
export const fetchTodos = async () => {
  const res = await fetch(`${import.meta.env.VITE_API_URL}/todos`);
  return res.json();
};

```

The `define` plugin in [`packages/vite/src/node/plugins/define.ts`](https://github.com/vitejs/vite/blob/main/packages/vite/src/node/plugins/define.ts) ensures that `import.meta.env.VITE_API_URL` is replaced with the actual string literal during the build process, eliminating any runtime lookup overhead.

## Security Best Practices

Vite's prefix filtering mechanism protects against common security pitfalls. However, you should follow these guidelines:

- **Never** remove the `envPrefix` restriction or set it to an empty string, as this would expose all environment variables (including `SECRET_TOKEN`, database URLs, etc.) to the client bundle.
- Keep sensitive keys in variables without the `VITE_` prefix (or your custom prefix) when you need them only in [`vite.config.ts`](https://github.com/vitejs/vite/blob/main/vite.config.ts) or server-side code.
- Remember that **all** values in `.env` files are embedded into the client bundle if they match the prefix. Do not store user-specific secrets or session tokens there.

## Summary

- Vite uses `import.meta.env` instead of `process.env` for client-side environment variables, with values replaced statically at build time by the `define` plugin in [`packages/vite/src/node/plugins/define.ts`](https://github.com/vitejs/vite/blob/main/packages/vite/src/node/plugins/define.ts).
- Only variables prefixed with `VITE_` (or your custom `envPrefix`) are exposed to the browser, protecting secrets from accidental leakage.
- TypeScript definitions in [`packages/vite/client.d.ts`](https://github.com/vitejs/vite/blob/main/packages/vite/client.d.ts) provide full IDE support for autocompletion and type checking.
- After modifying `.env` files, restart the dev server to reload variables via the `loadEnv` implementation.
- Customize the prefix in [`vite.config.ts`](https://github.com/vitejs/vite/blob/main/vite.config.ts) if `VITE_` does not match your naming conventions.

## Frequently Asked Questions

### Can I use process.env in Vite?

No. Vite does not polyfill `process.env` for client-side code. Instead, you must use `import.meta.env` to access environment variables. This design choice enables static analysis and tree-shaking, as the `define` plugin replaces these references with literal strings during the build process.

### Do I need to restart the dev server after changing .env files?

Yes. Vite loads environment files when the server starts using the `loadEnv` function. Changes to `.env`, `.env.local`, or mode-specific files are not hot-reloaded. You must stop and restart the development server (`npm run dev`) for new variables or modified values to become available in `import.meta.env`.

### How do I type custom env variables in TypeScript?

Vite provides type definitions in [`packages/vite/client.d.ts`](https://github.com/vitejs/vite/blob/main/packages/vite/client.d.ts) that declare the `ImportMetaEnv` interface. To add types for your custom variables, create a [`vite-env.d.ts`](https://github.com/vitejs/vite/blob/main/vite-env.d.ts) file in your `src` directory and use declaration merging:

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

interface ImportMetaEnv {
  readonly VITE_API_URL: string
  readonly VITE_APP_TITLE: string
}

interface ImportMeta {
  readonly env: ImportMetaEnv
}

```

This enables autocomplete and compile-time type checking for your **vite env variables**.

### Why are my env variables undefined in production?

If variables are `undefined` in production but work in development, the issue is usually the missing `VITE_` prefix (or your custom `envPrefix`). Vite strips all non-prefixed variables from the client bundle to prevent secret leakage. Verify that your variable starts with `VITE_` in the `.env` file and that you reference it correctly as `import.meta.env.VITE_YOUR_VAR` in your code.