02 / 06

Discuss environment-based configuration — mode, env files in vite

Vite uses modes and .env files for environment-based configuration: modes define the runtime context (development, production), while .env files provide environment-specific variables, with only VITE_ prefixed variables exposed to client code for security

Vite provides a powerful and flexible system for environment-based configuration through two complementary concepts: modes and environment variables. Modes define the context in which your application runs (e.g., development, production, staging), while environment variables (.env files) provide configuration values specific to each context. This separation allows you to build your application once and deploy it across multiple environments with different settings. Vite's approach emphasizes security by requiring explicit prefixes for client-exposed variables, preventing accidental leakage of sensitive server-side information [citation:2][citation:5].

Built-in Environment Variables
  1. 1

    import.meta.env.MODE: The mode the app is running in (development, production, or custom mode) [citation:2][citation:5]

  2. 2

    import.meta.env.BASE_URL: The base URL the app is being served from, determined by the base config option [citation:2][citation:5]

  3. 3

    import.meta.env.PROD: Boolean indicating whether the app is running in production [citation:2][citation:5]

  4. 4

    import.meta.env.DEV: Boolean indicating whether the app is running in development (always opposite of PROD) [citation:2][citation:5]

  5. 5

    import.meta.env.SSR: Boolean indicating whether the app is running on the server [citation:2][citation:5]

Modes are a core concept in Vite's environment system. By default, the dev server runs in development mode, and the build command runs in production mode. This means when you run vite build, Vite automatically loads variables from .env.production if it exists. However, you can override the default mode using the --mode flag. For example, vite build --mode staging will load .env.staging while still performing a production build (NODE_ENV remains 'production'). This separation between mode and NODE_ENV gives you fine-grained control over configuration without affecting build optimizations [citation:2][citation:6].

Mode-Based Configuration

Vite uses dotenv to load environment variables from files in your project root. The framework supports multiple file types with specific purposes and loading priorities. These files are automatically loaded at Vite startup, and changes require restarting the dev server [citation:2][citation:5][citation:6].

.env File Types
  1. 1

    .env: Loaded in all cases, contains base configuration [citation:2][citation:5]

  2. 2

    .env.local: Loaded in all cases but ignored by git (for local overrides) [citation:2][citation:5]

  3. 3

    .env.[mode]: Only loaded in the specified mode (e.g., .env.production, .env.staging) [citation:2][citation:5]

  4. 4

    .env.[mode].local: Mode-specific local overrides, ignored by git [citation:2][citation:5]

Environment variables are loaded with a specific priority order. Variables from mode-specific files (e.g., .env.production) take precedence over generic files (.env). Local files (.env.local, .env.[mode].local) have even higher priority for developer-specific overrides. However, the highest priority of all goes to environment variables already set in the shell when Vite is executed—for example, running VITE_SOME_KEY=123 vite build will override any value in .env files [citation:2][citation:5][citation:6].

A critical security feature in Vite is that only environment variables prefixed with VITE_ are exposed to client-side code. Variables without this prefix are only available in server-side contexts like vite.config.js. This prevents accidental exposure of sensitive information like database passwords or API keys in the browser. When accessed in client code, these variables are statically replaced at build time—they don't actually exist as runtime environment variables [citation:2][citation:5][citation:6].

VITE_ Prefix Example

It's crucial to understand that NODE_ENV and mode are two different concepts in Vite. NODE_ENV (process.env.NODE_ENV) primarily controls build optimizations and framework behavior, while mode determines which .env file is loaded. This distinction allows you to have, for example, a staging build that runs with production optimizations (NODE_ENV=production) but uses staging-specific configuration loaded from .env.staging [citation:2][citation:5][citation:6].

NODE_ENV and Mode Combinations

For better developer experience, Vite allows you to add TypeScript type definitions for your custom environment variables. Create a vite-env.d.ts file in your src directory and augment the ImportMetaEnv interface. This provides autocompletion and type checking when using import.meta.env in your code [citation:2][citation:5][citation:6].

TypeScript Configuration

Vite also supports environment variable replacement in HTML files using a special %ENV_NAME% syntax. This is useful for setting meta tags, titles, or other HTML attributes based on environment. Variables that don't exist are left untouched, unlike JavaScript where they'd become undefined [citation:2][citation:5][citation:6].

HTML Variable Replacement

Vite uses dotenv-expand to support variable expansion within .env files. This allows you to reference other variables, making configuration more DRY. However, if you need to use the $ character literally, you must escape it with a backslash [citation:2][citation:5].

Variable Expansion Examples

When working with environment variables in Vite, follow these security practices: Never store sensitive information in VITE_* prefixed variables—they end up in client bundles. Use .env.local and .env.*.local files for local overrides and ensure they're in .gitignore. For production secrets, use actual server environment variables or a secrets management service. Remember that .env files are for development convenience, not secure secret storage [citation:2][citation:5][citation:6].

Difficulty: 6/10
Topics: environment variables, Vite config modes, .env file loading

Scenario Questions

0-2 years experience
  1. 1

    You're setting up a new Vite project and need to connect to a test API endpoint. You've added VITE_API_URL=https://test-api.example.com to .env, but when you log process.env.VITE_API_URL in your app, it's undefined. What's the most likely cause and how do you fix it?

  2. 2

    You're told to switch your Vite app from development to production mode. What files do you need to create, and what changes in behavior should you expect when you run build vs dev?

2-5 years experience
  1. 1

    Your team’s staging environment broke after a deploy — the API calls are pointing to localhost instead of the staging URL. You checked the .env file and it looks correct. What steps would you take to debug this?

  2. 2

    A developer added a sensitive token to .env.local and pushed it to Git. How would you explain why this is dangerous in Vite, and what’s the right way to handle secrets in a frontend app?

5-8 years experience
  1. 1

    You're building a multi-tenant SaaS app where each tenant has a different API base URL. Vite inlines env vars at build time — how would you design a system that allows dynamic tenant configuration without rebuilding the app for each customer?

  2. 2

    In a monorepo with 10+ Vite apps, each needing slightly different env configs for dev/staging/prod, how would you structure the .env files and config to avoid duplication and reduce deployment risk?

8+ years experience
  1. 1

    We're migrating from Webpack to Vite and need to preserve legacy env-based feature flags that were evaluated at runtime. How would you architect a solution that maintains backward compatibility while leveraging Vite's build-time env inlining?

  2. 2

    Your company has strict compliance requirements: no secrets in source control, and env vars must be injected at container runtime. How would you design a CI/CD pipeline and Vite config to securely inject secrets into a frontend app without exposing them in build artifacts or logs?

Follow-up Questions

  • What happens if you forget the VITE_ prefix on an env variable?
  • How would you debug a situation where an env variable is undefined in production but works locally?
  • Why can't you access process.env.VITE_API_KEY in the browser console even if it's defined in .env?