Skip to the content.

Handling Environment Variables in Vue

Vue uses the widely adopted dotenv module to load build configuration from the following files in your environment directory:

.env                # loaded in all cases
.env.local          # loaded in all cases, ignored by git
.env.[mode]         # only loaded in specified mode
.env.[mode].local   # only loaded in specified mode, ignored by git

Each file has the following format

VITE_SOME_KEY=123
DB_PASSWORD=secret

Everything that has the VITE_ prefix will automatically be available in the client application inside import.meta.env

<script setup>
console.log(import.meta.env.VITE_SOME_KEY) // "123"
</script>

Other parts of the application can securely use the .dotenv file without the VITE_ prefix so variables will not leak to the client.

That was easy so far. In a real-life scenario, you will have multiple config files for each environment.

For example locally

# .env.local
VITE_BACKEND_URL=http://localhost:3000/
VITE_PUBLIC_URL=http://localhost:3000/uploads/

And for production

# .env.production
VITE_BACKEND_URL=http://example.com/
VITE_PUBLIC_URL=http://example.cloudflare.com/uploads/

On the client side, we can use these variables directly since they are globally available

// /lib/fetch.ts

import axios from "axios";

const instance = axios.create({
  baseURL: import.meta.env.VITE_BACKEND_URL,
});

In case you are using typescript (you should, right?) you might see a not-that-helpful error

Property 'env' does not exist on type 'ImportMeta'.ts(2339)

To make TS happy create the file src/types/vite-env.d.ts with the following content.

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

interface ImportMetaEnv {
  readonly VITE_PUBLIC_URL: string;
  readonly VITE_BACKEND_URL: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}

Lastly, I find it a bit verbose to refer to import.meta.env.VITE_BACKEND_URL in my code. I usually create an intermediate appSettings.ts file to encapsulate it.

// src/config/appSetings.ts

export default {
  baseURL: import.meta.env.VITE_BACKEND_URL,
  publicUrl: import.meta.env.VITE_PUBLIC_URL,
};

which makes our original code simpler.

import axios from "axios";
import { baseUrl } from "@/config/appSetings"

const instance = axios.create({
  baseURL,
});

Ref: Fotis Adamakis - Medium