ArkEnv

Typing import.meta.env

For most use cases, you'll want to access your environment variables in your client code. In a Vite project, this is done via import.meta.env.

With ArkEnv, this can be typesafe with the one-time setup below. After this, each time you add/remove environment variables from your schema, your import.meta.env will always be typesafe - no codegen needed.

Link to section: setupSetup

Important

You must have the core arkenv package installed as a dependency in your project. See ArkEnv quickstart for instructions.

Add this to a vite-env.d.ts file in your src directory:

src/vite-env.d.ts
/// <reference types="vite/client" />

type ImportMetaEnvAugmented =
	import("@arkenv/vite-plugin").ImportMetaEnvAugmented<
		typeof import("../vite.config").Env
	>;

interface ViteTypeOptions {
	// By adding this line, you can make the type of ImportMetaEnv strict
	// to disallow unknown keys.
	// See: https://vite.dev/guide/env-and-mode#intellisense-for-typescript
	// ⚠️ This option requires Vite 6.3.x or higher
	strictImportMetaEnv: unknown;
}

// Augment import.meta.env with your schema
// Only `VITE_*` prefixed variables will be included
interface ImportMetaEnv extends ImportMetaEnvAugmented {}

Link to section: usageUsage

Once set up, import.meta.env is fully typesafe:

src/app.tsx
// TypeScript knows about your VITE_* variables
const apiUrl = import.meta.env.VITE_API_URL; // ✅ Typesafe
const port = import.meta.env.PORT; // ❌ Error: PORT is not in ImportMetaEnv

// Autocomplete works too!
import.meta.env.VITE_ // Shows all your VITE_* variables

Link to section: how-it-worksHow it works

The ImportMetaEnvAugmented type:

  1. Extracts the inferred type from your schema (the result of type() from arkenv)
  2. Filters to only include variables matching the Vite prefix (defaults to "VITE_")
  3. Makes them available on import.meta.env with full type safety

Server-only variables (like PORT) are automatically excluded from the client bundle and won't appear in import.meta.env.

Read more in the Vite documentation.

Link to section: as-your-project-growsAs your project grows

You might want to define your schema in a dedicated file for better organization:

src/env.ts
import { type } from "arkenv";

export const Env = type({
	PORT: "number.port",
	VITE_API_URL: "string",
	VITE_API_KEY: "string",
	VITE_MY_NUMBER: "number",
	VITE_MY_BOOLEAN: "boolean",
});

export type Env = typeof Env.infer;
vite.config.ts
import arkenvVitePlugin from "@arkenv/vite-plugin";
import { defineConfig } from "vite";
import { Env } from "./src/env";

export default defineConfig({
	plugins: [arkenvVitePlugin(Env)],
});
src/vite-env.d.ts
/// <reference types="vite/client" />

type ImportMetaEnvAugmented =
	import("@arkenv/vite-plugin").ImportMetaEnvAugmented<
		typeof import("./env").Env
	>;

interface ViteTypeOptions {
	strictImportMetaEnv: unknown;
}

interface ImportMetaEnv extends ImportMetaEnvAugmented {}

Important

Imports will break type augmentation

If the ImportMetaEnv augmentation does not work, make sure you do not have any import statements in vite-env.d.ts. See the TypeScript documentation for more information.

Link to section: creditCredit

This implementation is inspired by vite-plugin-validate-env by Julien-R44.