Answer questions about ArkEnv and help implement environment variable validation. Use when developers: (1) Ask about environment variable validation or typesafety, (2) Want to setup ArkEnv in a project, (3) Need to define or update schemas using ArkType or Standard Schema, (4) Are integrating with Next.js, Nuxt, Vite, Bun, or Node.js runtimes. Triggers on: 'ArkEnv', 'env validation', 'typesafe env', 'createEnv', 'env.ts', 'arkenv'.
82%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
ArkEnv is a typesafe environment variable validation library for modern JavaScript and TypeScript frameworks. It provides a single canonical surface across all frameworks: import { env } from "./env".
In v1, ArkEnv offers two first-class validation engines:
@arkenv/core: Built-in ArkType DSL engine for high-performance schema definition and automatic coercion.@arkenv/standard: Standard Schema engine supporting any compliant validator (Zod, Valibot, etc.).@arkenv/core ArkType DSL strings or @arkenv/standard with Zod / Valibot.string.numeric, number.port, booleans, JSON objects, arrays) and default values ("boolean = true").env directly across frontend and backend code.@arkenv/vite-plugin): Plugin operates in transform mode, rewriting imports from env.ts in the client graph to inline public VITE_* literals and replacing private server keys with throwing runtime guards.@arkenv/bun-plugin): Plugin intercepts env.ts imports in Bun.build / Bun.serve to inline public BUN_PUBLIC_* values while guarding server secrets.@arkenv/nextjs): Build-time and runtime validation with automatic client/server isolation proxy.@arkenv/nuxt): Nuxt module with Nitro boot validation and runtime proxy guard.@arkenv/core or @arkenv/standard.pnpm dlx arkenv init (or npx arkenv init).Next.js, Nuxt, Vite, Bun, etc.) and scaffold env.ts.--preset, -P <provider>).tsconfig.json when needed. Schema discovery for CLI commands uses --schema or flat convention paths (env.ts, src/env.ts) — not a package.json "arkenv" field, and not leftover split-layout filenames such as env/server.ts.ArkEnv is code-first. You can select a hosting provider preset during initial project setup (--preset vercel, netlify, cloudflare, railway, render, fly) or copy-paste provider fields directly into ./env.ts from the documentation (/docs/core-concepts/hosting-presets). There are no machine-managed comment blocks or CLI mutation commands.
AI agents SHOULD always use the CLI for project initialization to ensure consistency and reliability. Use the --agent flag for a fully automated, machine-readable experience.
pnpm dlx arkenv init --agent--agent flag automatically enables the following behaviors:
--yes: Bypasses all interactive prompts and uses recommended defaults.--quiet: Suppresses spinners and ANSI formatting for cleaner terminal logs.--json: Emits a structured JSON summary to stdout upon completion (all other output is sent to stderr).stdout. Success is ok: true with commandId: "init"; details (e.g. scaffolded paths) live under result.ok: false)--agent never implies --force. When a safety check trips, the CLI refuses and emits an errored settlement envelope to stdout:
{
"ok": false,
"commandId": "init",
"error": {
"code": "CLI.GIT_TREE_DIRTY",
"severity": "error",
"summary": "Git working tree is not clean.",
"why": "Commit or stash your changes before running arkenv init.",
"nextActions": [
{
"kind": "run-command",
"label": "Re-run with --force to bypass git working tree check",
"command": "arkenv init --force"
}
]
},
"diagnostics": [],
"nextActions": [
{
"kind": "run-command",
"label": "Re-run with --force to bypass git working tree check",
"command": "arkenv init --force"
}
]
}error.code: a stable dotted identifier you can branch on (CLI.REQUIREMENTS_NOT_MET, CLI.GIT_TREE_DIRTY, CLI.NON_EMPTY_DIR, …). CLI.INTERNAL_ERROR means the CLI broke rather than refused — retrying with flags will not help.nextActions: remediation steps. A run-command action that includes --force means the refusal is bypassable; empty nextActions means it is not.Escalation pattern: always run init --agent without --force first. If you get ok: false, inspect error.code and nextActions. Only re-run with --force (or the command from a run-command action) once you have deliberately decided the refusal is safe to bypass — do not add --force pre-emptively.
initSet up ArkEnv in your project. It detects your framework and configures the appropriate plugin and schema.
pnpm dlx arkenv init [options]--preset, -P <preset>: Specify hosting provider preset (none, vercel, netlify, cloudflare, railway, render, fly).--no-codegen: Disable Next.js codegen configuration setup.--force, -f: Bypass clean git working tree safety check.checkValidate the environment against your schema file.
pnpm arkenv check [options]--schema, -s <path>: Explicit path to the schema module (overrides convention discovery).--verify-example [file]: Verify that all declared schema keys are present in .env.example (or a custom example file path) without mutating files.--env-file <path>: Specify one or more custom environment files to load.--json: Output structured JSON diagnostics to stdout.env@arkenv/core (ArkType DSL)import arkenv from "@arkenv/core";
export const env = arkenv({
PORT: "number.port = 3000",
DATABASE_URL: "string",
VITE_API_URL: "string",
NODE_ENV: "'development' | 'production' | 'test' = 'development'",
});@arkenv/standard (Standard Schema: Zod, Valibot)import arkenv from "@arkenv/standard";
import * as z from "zod";
export const env = arkenv({
PORT: z.number().default(3000),
DATABASE_URL: z.string(),
VITE_API_URL: z.url(),
NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
});Valibot uses the /valibot subpath (install @valibot/to-json-schema as well):
import { arkenv } from "@arkenv/standard/valibot";
import * as v from "valibot";
export const env = arkenv({
PORT: v.optional(v.number(), 3000),
DATABASE_URL: v.pipe(v.string(), v.url()),
});env in Application CodeAlways import and read properties directly from the canonical env object:
import { env } from "./env";
export default function App() {
const apiUrl = env.VITE_API_URL; // string
return <div>API URL: {apiUrl}</div>;
}@arkenv/vite-plugin)Register the plugin in vite.config.ts without schema arguments:
import { defineConfig } from "vite";
import arkenvPlugin from "@arkenv/vite-plugin";
export default defineConfig({
plugins: [arkenvPlugin()],
});If you need environment variables inside vite.config.ts itself (e.g. server.port), validate them with loadEnv:
import { defineConfig, loadEnv } from "vite";
import arkenvPlugin from "@arkenv/vite-plugin";
import arkenv, { type } from "@arkenv/core";
export const Env = type({
PORT: "number.port = 5173",
VITE_API_URL: "string",
});
export default defineConfig(({ mode }) => {
const env = arkenv(Env, { env: loadEnv(mode, process.cwd(), "") });
return {
plugins: [arkenvPlugin()],
server: { port: env.PORT },
};
});@arkenv/bun-plugin)In bunfig.toml:
[serve.static]
plugins = ["@arkenv/bun-plugin"]In Bun.build:
import arkenvPlugin from "@arkenv/bun-plugin";
await Bun.build({
entrypoints: ["./src/index.tsx"],
outdir: "./dist",
plugins: [arkenvPlugin],
});src/env.ts contains all keys. Server graph runs full validation at boot; client graph receives inlined public literals while access to private server keys throws a runtime error.extends: [clientEnv]. Next can use import "server-only" + @arkenv/core for the server module. Nuxt: never import the server module from client code. Not a CLI --strict flag or package /client /server surface.import { env } from "./env": Never use import.meta.env or process.env directly for application environment variables in v1..d.ts augmentations: ImportMetaEnvAugmented and ProcessEnvAugmented are legacy v0 patterns dropped in v1.DATABASE_URL, API_SECRET_KEY) with client prefixes (VITE_, NEXT_PUBLIC_, BUN_PUBLIC_, NUXT_PUBLIC_).onmax/nuxt-skills
2e74504
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.