Skip to main

Inject Environment Variables into index.html file in Vite

4 min read

While we can easily import and use .env values in our JS/TS files, Vue <script> etc. in Vite, there isn’t exactly a straightforward way to inject these values in our index.html file since we cannot directly access import.meta.env in that file.

Let’s say we have an .env file from which we need to access a specific variable value and use it in a <meta> property or maybe a script tag where the api key needs to be appended to src url.

For Example,

.env file:

VITE_API_KEY=foo

index.html file:

<meta name="SOME_THIRD_PARTY" content="foo" />
<script src="https://awesomethirdparty.library/v1/script.js?VITE_API_KEY=foo"></script>
<!-- or a <div data-xyz-api-key="foo"> somewhere in the html file -->

Method 1: Using Vite Plugin API

Vite.js comes with a highly configurable plugin API system. Let’s create a custom vite plugin that utilises transformIndexHtml hook which gives us access to contents of index.html file as string. We’ll also use loadEnv function from vite to load the required .env file and access its values in our custom plugin.

Also note the prefix VITE_ to our environment variables, by default vite will only return the environment variables prefixed with VITE_ you can customise that (not recommended) using envPrefix config.

In the index.html file let’s add a placeholder text that is unique across our html file and can be replaced easily with String.prototype.replace() in our custom vite plugin.

index.html file:

<meta name="SOME_THIRD_PARTY" content="$API_KEY_PLACEHOLDER" />
<script src="https://awesomethirdparty.library/v1/script.js?API_KEY=$API_KEY_PLACEHOLDER"></script>
<!-- or a <div data-xyz-api-key="$API_KEY_PLACEHOLDER"> somewhere in the html file -->

Let’s create an injectHtml.ts file in the root of the project directory. (you also might need to add this files into include array in your tsconfig.node.json file if you’re using Typescript)

injectHtml.ts:

import type { PluginOption } from "vite";
import { loadEnv } from "vite";

export const injectEnvIntoHtmlPlugin = (): PluginOption => {
  const env = loadEnv("production", ".");
  return {
    name: "inject-env-html",
    transformIndexHtml(html: string) {
      return html.replace("$API_KEY_PLACEHOLDER", env["VITE_API_KEY"]);
    },
  };
};

tsconfig.node.json file:

{
  "compilerOptions": {
    //...
  },
  "include": ["vite.config.ts", "injectHtml.ts"]
}

Add the plugin to vite.config.ts

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { injectEnvIntoHtmlPlugin } from "./injectHtml";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(), injectEnvIntoHtmlPlugin()],
});

If we run the vite server and check index.html file in the browser:

Environment Variable loaded into meta tag

Note: loadEnv only returns env values prefixed with VITE_ and also since we are using .env as the name for our environment variable file it’s loaded into both production and development modes vite is running in and you might want to change based on your requirement.

Method 2: Teleport/Portal into index.html

We can utilise frameworks Teleport (Portal in react) to easily insert html content anywhere in the index.html with a selector. First we load the required env value into our script and then use teleport to inject it into the html.

<script setup lang="ts">
const apiKey = import.meta.env.VITE_API_KEY;
</script>
<template>
  <Teleport to="head">
    <meta name="SOME_THIRD_PARTY" :content="apiKey" />
  </Teleport>
  <!-- you could also document.getElementById and appendChild instead of Teleport at this point -->
</template>

Drawbacks of this approach is your api key won’t be available on initial page load (i.e here the meta tag with apiKey would be loaded into html only after vue is loaded and initialised). Also at this point instead of Teleport you could also just document.getElementById or document.querySelector in your framework and inject the apiKey too.

Method 3: vite-plugin-html-env

Using vite-plugin-html-env, this works similar to Method 1. Just install the plugin and add a comment in index.html file that includes .env KEY.

yarn add -D vite-plugin-html-env

vite.config.ts:

import VitePluginHtmlEnv from "vite-plugin-html-env";
import vue from "@vitejs/plugin-vue";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [VitePluginHtmlEnv(), vue()],
});

index.html:

<meta name="SOME_THIRD_PARTY" content="<{ VITE_API_KEY }>" />

Update Vite 4.2 and above

Since Vite 4.2, this feature is supported natively and we can use %VITE_API_KEY% syntax in our HTML.

Further Reading / References: