Vite

Learn how to use ArkEnv in a Vite project.

Edit on GitHub

@arkenv/vite-plugin validates during Vite dev and production builds. Transform mode inlines public VITE_ keys into the client bundle and keeps server secrets out.

When does validation run?

When @arkenv/vite-plugin is registered, it discovers and validates env.ts during Vite config resolution. An invalid or missing value aborts the dev server or production build before Vite reports that it is ready. Relevant .env and schema changes are validated again during HMR.

Without the plugin, validation is import-driven: env.ts runs when an application module imports it. This distinction applies to both server and client graphs; the plugin is what lets Vite validate the schema before the graph is ready and transform client imports safely. See the @arkenv/vite-plugin reference for the plugin contract.

This documents the existing fail-fast behavior. ArkEnv does not add a default-off lazy-validation flag; a separate lazy mode would be an intentionally scoped feature.

For high-level architectural trade-offs, see Frameworks.

Quickstart

Scaffold Vite integration in an existing project using the CLI:

npx arkenv init
pnpm dlx arkenv init
yarn dlx arkenv init
bunx arkenv init

The CLI installs @arkenv/vite-plugin, configures vite.config.ts, and scaffolds your initial env.ts schema file.

Manual installation

If you prefer manual setup, install @arkenv/vite-plugin alongside your chosen validation engine.

ArkType engine

Install @arkenv/core, arktype, and the Vite plugin:

npm install @arkenv/core arktype
npm install -D @arkenv/vite-plugin
pnpm add @arkenv/core arktype
pnpm add -D @arkenv/vite-plugin
yarn add @arkenv/core arktype
yarn add --dev @arkenv/vite-plugin
bun install @arkenv/core arktype
bun install --dev @arkenv/vite-plugin

Standard Schema engine

If you aren't using ArkType, install @arkenv/standard:

npm install @arkenv/standard
npm install -D @arkenv/vite-plugin
pnpm add @arkenv/standard
pnpm add -D @arkenv/vite-plugin
yarn add @arkenv/standard
yarn add --dev @arkenv/vite-plugin
bun install @arkenv/standard
bun install --dev @arkenv/vite-plugin

Configuration

Add the plugin to your vite.config.ts.

Register the plugin

Import and register the plugin in your Vite plugins array:

./vite.config.ts
import {  } from "vite";
import  from "@arkenv/vite-plugin";

export default ({
  : [()],
});

If you aren't using ArkType, import the plugin from @arkenv/vite-plugin/standard.

Define your schema

Create an env.ts file in your source tree. Import from @arkenv/core (or @arkenv/standard); the arkenv package is CLI-only:

./env.ts
import  from "@arkenv/core";

export const  = ({
  : "string",
  : "string",
  : "'development' | 'production' | 'test' = 'development'",
});

Import { env } from "./env" across your application. In server contexts (such as SSR or development scripts), the real validation module runs at boot. In client bundles, the Vite plugin rewrites the import to inline public VITE_ values and guards private server keys.

Reuse the schema in Vite config

Vite does not load .env* files while evaluating vite.config.ts. When the config needs typed values (for example server.port), compile a reusable schema with type() and validate it with core arkenv() and loadEnv. Register the plugin with no schema argument — it still rewrites env.ts in the client graph.

./vite.config.ts
import { ,  } from "vite";
import  from "@arkenv/vite-plugin";
import , {  } from "@arkenv/core";

export const  = ({
  : "number.port = 5173",
  : "string",
  : "string",
});

export default (({  }) => {
  const  = (, { : (, .(), "") });
  return {
    // Plugin is transform-only — no schema argument
    : [()],
    : { : . },
  };
});

Learn more in Reusing schemas.

Client access

Import the validated env object from your schema module.

Do not read import.meta.env directly

Reading import.meta.env skips ArkEnv. Import { env } so public keys stay typed and coerced and server secrets stay out of the client bundle.

Types and options: @arkenv/vite-plugin.

SSR and dual-graph execution

Vite maintains two distinct module graphs when building and serving full-stack or SSR applications:

  • Server graph: During SSR execution and dev server requests, env.ts executes real @arkenv/core runtime validation at boot. It ensures private secrets (such as DATABASE_URL) and public configuration validate before handling requests.
  • Client graph: During client compilation, @arkenv/vite-plugin intercepts and transforms env.ts. It inlines public VITE_* values as static literals and replaces private server keys with throwing runtime stubs. Client bundles omit the validator engine.

On Vite 6+, the Environment API drives this split: server consumers and custom ssr environments keep the real module, everything else gets the client rewrite. On Vite 4 and 5, the plugin falls back to the legacy SSR transform flag.

Next steps