Frameworks

Validate environment variables in Next.js, Nuxt, Vite, TanStack Start, and Bun with ArkEnv.

Edit on GitHub

ArkEnv works in any JavaScript or TypeScript project. When you build full-stack applications, client bundles must never receive server secrets. The framework packages below enforce that boundary during development and production builds.

Choose your framework to get started:

How hosts enforce the boundary

Frameworks use compile-time AST transforms or host runtime adapters:

FrameworkIntegration strategyClient bundle outputSSR and server validationPublic env without rebuild (Docker)
Next.jsHost adapter + codegen (@arkenv/nextjs)Generated runtime proxyProcess boot (process.env)Requires rebuild for NEXT_PUBLIC_*
NuxtNitro plugin (@arkenv/nuxt)Dynamic runtimeConfig hydrationNitro server boot gateYes (via Nitro runtimeConfig)
ViteAST build transform (@arkenv/vite-plugin)Inlined public literals + throwing stubsFull @arkenv/core at server bootRequires rebuild for VITE_*
TanStack StartAST build transform (@arkenv/vite-plugin / @arkenv/rsbuild-plugin)Inlined public literals + throwing stubsFull @arkenv/core at server bootRequires rebuild for VITE_* / PUBLIC_*
BunBundler AST transform (@arkenv/bun-plugin)Inlined public literals + throwing stubsFull @arkenv/core at server bootRequires rebuild for BUN_PUBLIC_*

Vite, TanStack Start, and Bun evaluate two module graphs in full-stack and SSR apps. Application code imports @arkenv/core (or @arkenv/standard); the plugin rewrites the client graph so public keys inline and server secrets become throwing stubs. Next.js and Nuxt use host adapters (@arkenv/nextjs, @arkenv/nuxt) with dedicated entrypoints and codegen or runtimeConfig hydration.

ArkEnv keeps the validation engine (@arkenv/core / @arkenv/standard) as an optional peer of each host adapter. You install the engine you use; the adapter does not bundle either runtime. That keeps host packages lean and lets you pair any adapter with ArkType or a Standard Schema validator.

Loading .env files

ArkEnv does not read .env files. Something else must load them before arkenv() runs.

Next.js, Nuxt, Vite, and Bun already load .env* files. On plain Node (20.6+), use the built-in --env-file flag:

Terminal
node --env-file=.env dist/index.js

For TypeScript in development, pass the same flag to your usual runner:

Terminal
tsx --env-file=.env src/index.ts

For NestJS applications, @nestjs/cli 11+ supports nest start --env-file .env — follow the Use with NestJS guide.

After values are in process.env (or a custom record), arkenv() validates them.