arkenv

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

ArkEnv

ArkEnv

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 是面向现代 JavaScript 和 TypeScript 框架的类型安全环境变量校验库。它提供 跨所有框架的统一规范入口:
import { env } from "./env"
。
在 v1 中,ArkEnv 提供两个一等验证引擎:
  • @arkenv/core
    :内置 ArkType DSL 引擎,用于高性能 Schema 定义和自动类型转换。
  • @arkenv/standard
    :Standard Schema 引擎,支持任何符合规范的验证器(Zod、Valibot 等)。

Capabilities

功能

Core usage

核心用法

  • Define typesafe schemas using
    @arkenv/core
    ArkType DSL strings or
    @arkenv/standard
    with Zod / Valibot.
  • Automatic coercion (
    string.numeric
    ,
    number.port
    , booleans, JSON objects, arrays) and default values (
    "boolean = true"
    ).
  • Single, uniform developer experience: import
    env
    directly across frontend and backend code.
  • 使用
    @arkenv/core
    的 ArkType DSL 字符串,或使用
    @arkenv/standard
    配合 Zod / Valibot 定义类型安全的 Schema。
  • 自动类型转换(
    string.numeric
    、
    number.port
    、布尔值、JSON 对象、数组)和默认值(
    "boolean = true"
    )。
  • 统一一致的开发体验:在前端和后端代码中直接导入
    env
    。

Framework integration

框架集成

  • Vite (
    @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.
  • Bun (
    @arkenv/bun-plugin
    ): Plugin intercepts
    env.ts
    imports in
    Bun.build
    /
    Bun.serve
    to inline public
    BUN_PUBLIC_*
    values while guarding server secrets.
  • Next.js (
    @arkenv/nextjs
    ): Build-time and runtime validation with automatic client/server isolation proxy.
  • Nuxt (
    @arkenv/nuxt
    ): Nuxt module with Nitro boot validation and runtime proxy guard.
  • Node.js: Direct boot-time validation via
    @arkenv/core
    or
    @arkenv/standard
    .
  • Vite(
    @arkenv/vite-plugin
    ):插件以 transform 模式运行,将客户端图(client graph)中来自
    env.ts
    的导入重写为内联的公共
    VITE_*
    字面量,并将私有服务端密钥替换为访问时抛出错误的运行时守卫。
  • Bun(
    @arkenv/bun-plugin
    ):插件拦截
    Bun.build
    /
    Bun.serve
    中的
    env.ts
    导入,内联公共
    BUN_PUBLIC_*
    值,同时守卫服务端密钥。
  • Next.js(
    @arkenv/nextjs
    ):提供构建时和运行时验证,并自动创建客户端/服务端隔离代理。
  • Nuxt(
    @arkenv/nuxt
    ):Nuxt 模块支持 Nitro 启动验证和运行时代理守卫。
  • Node.js:通过
    @arkenv/core
    或
    @arkenv/standard
    直接在启动时进行验证。

CLI (setup & DevOps)

CLI(设置与 DevOps)

  • Initialize ArkEnv in new or existing projects using
    pnpm dlx arkenv init
    (or
    npx arkenv init
    ).
  • Automatically detect frameworks (
    Next.js
    ,
    Nuxt
    ,
    Vite
    ,
    Bun
    , etc.) and scaffold
    env.ts
    .
  • Select hosting provider preset during init (
    --preset, -P <provider>
    ).
  • Automatically configure
    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
    .
  • 使用
    pnpm dlx arkenv init
    (或
    npx arkenv init
    )在新建或现有项目中初始化 ArkEnv。
  • 自动检测框架(
    Next.js
    、
    Nuxt
    、
    Vite
    、
    Bun
    等)并生成
    env.ts
    脚手架。
  • 初始化期间选择托管提供商预设(
    --preset, -P <provider>
    )。
  • 根据需要自动配置
    tsconfig.json
    。CLI 命令的 Schema 发现机制使用
    --schema
    或扁平约定路径(
    env.ts
    、
    src/env.ts
    ),而不是
    package.json
    中的
    "arkenv"
    字段,也不使用
    env/server.ts
    等旧版拆分布局文件名。

Hosting presets

托管提供商预设

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.
ArkEnv 采用 code-first 模式。你可以在初始项目设置期间选择托管提供商预设(
--preset vercel
、
netlify
、
cloudflare
、
railway
、
render
、
fly
),也可以从文档(
/docs/core-concepts/hosting-presets
)中直接复制提供商字段到
./env.ts
。不存在由机器管理的注释块或 CLI 变更命令。

Agent setup (machine-readable)

Agent 设置(机器可读)

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.
  • Command:
    pnpm dlx arkenv init --agent
  • Behavior: The
    --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
      ).
  • Success Verification: Parse the JSON settlement envelope on
    stdout
    . Success is
    ok: true
    with
    commandId: "init"
    ; details (e.g. scaffolded paths) live under
    result
    .
AI Agent 应始终使用 CLI 初始化项目,以确保一致性和可靠性。使用
--agent
标志可获得全自动、机器可读的体验。
  • 命令:
    pnpm dlx arkenv init --agent
  • 行为:
    --agent
    标志会自动启用以下行为:
    • --yes
      :跳过所有交互式提示,并使用推荐默认值。
    • --quiet
      :抑制 spinner 和 ANSI 格式化,使终端日志更加简洁。
    • --json
      :完成后向
      stdout
      输出结构化 JSON 摘要(所有其他输出发送到
      stderr
      )。
  • 成功验证:解析
    stdout
    上的 JSON settlement envelope。成功时为
    ok: true
    且
    commandId: "init"
    ;详细信息(例如已生成的路径)位于
    result
    中。

Handling refusals (
ok: false
)

处理拒绝(
ok: false
)

--agent
never implies
--force
. When a safety check trips, the CLI refuses and emits an errored settlement envelope to
stdout
:
json
{
  "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.

--agent
绝不隐含
--force
。当安全检查触发时,CLI 会拒绝执行,并向
stdout
输出错误的 settlement envelope:
json
{
  "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
    :可用于分支判断的稳定点分标识符(
    CLI.REQUIREMENTS_NOT_MET
    、
    CLI.GIT_TREE_DIRTY
    、
    CLI.NON_EMPTY_DIR
    等)。
    CLI.INTERNAL_ERROR
    表示 CLI 本身发生故障,而不是主动拒绝执行——重新尝试并添加标志不会有帮助。
  • nextActions
    :补救步骤。包含
    --force
    的
    run-command
    操作表示可以绕过此次拒绝;
    nextActions
    为空则表示无法绕过。
升级处理模式:始终先运行
init --agent
,不要预先添加
--force
。如果返回
ok: false
,请检查
error.code
和
nextActions
。只有在明确判断绕过拒绝是安全操作后,才使用
--force
或
run-command
操作中的命令重新运行。

CLI commands

CLI 命令

init

init

Set up ArkEnv in your project. It detects your framework and configures the appropriate plugin and schema.
bash
pnpm dlx arkenv init [options]
在项目中设置 ArkEnv。CLI 会检测框架并配置相应的插件和 Schema。
bash
pnpm dlx arkenv init [options]

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.
  • --preset, -P <preset>
    :指定托管提供商预设(none、vercel、netlify、cloudflare、railway、render、fly)。
  • --no-codegen
    :禁用 Next.js codegen 配置设置。
  • --force, -f
    :绕过 Git 工作树必须保持干净的 safety check。

check

check

Validate the environment against your schema file.
bash
pnpm arkenv check [options]
根据 Schema 文件验证环境变量。
bash
pnpm arkenv check [options]

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.

  • --schema, -s <path>
    :显式指定 Schema 模块路径(覆盖约定发现机制)。
  • --verify-example [file]
    :验证所有已声明的 Schema 键是否都存在于
    .env.example
    或自定义示例文件路径中,且不会修改文件。
  • --env-file <path>
    :指定一个或多个要加载的自定义环境变量文件。
  • --json
    :向 stdout 输出结构化 JSON 诊断信息。

Defining Schemas & Importing
env

定义 Schema 与导入
env

@arkenv/core
(ArkType DSL)

@arkenv/core
(ArkType DSL)

ts
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'",
});
ts
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)

@arkenv/standard
(Standard Schema:Zod、Valibot)

ts
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):
ts
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()),
});
ts
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 使用
/valibot
子路径(还需安装
@valibot/to-json-schema
):
ts
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()),
});

Consuming
env
in Application Code

在应用代码中使用
env

Always import and read properties directly from the canonical
env
object:
tsx
import { env } from "./env";

export default function App() {
  const apiUrl = env.VITE_API_URL; // string
  return <div>API URL: {apiUrl}</div>;
}

始终直接从规范
env
对象导入并读取属性:
tsx
import { env } from "./env";

export default function App() {
  const apiUrl = env.VITE_API_URL; // string
  return <div>API URL: {apiUrl}</div>;
}

Framework Setup Patterns

框架设置模式

1. Vite (
@arkenv/vite-plugin
)

1. Vite(
@arkenv/vite-plugin
)

Register the plugin in
vite.config.ts
without schema arguments:
ts
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
:
ts
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 },
  };
});
在
vite.config.ts
中注册插件,无需传入 Schema 参数:
ts
import { defineConfig } from "vite";
import arkenvPlugin from "@arkenv/vite-plugin";

export default defineConfig({
  plugins: [arkenvPlugin()],
});
如果需要在
vite.config.ts
内部使用环境变量(例如
server.port
),请使用
loadEnv
对其进行验证:
ts
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 },
  };
});

2. Bun (
@arkenv/bun-plugin
)

2. Bun(
@arkenv/bun-plugin
)

In
bunfig.toml
:
toml
[serve.static]
plugins = ["@arkenv/bun-plugin"]
In
Bun.build
:
ts
import arkenvPlugin from "@arkenv/bun-plugin";

await Bun.build({
  entrypoints: ["./src/index.tsx"],
  outdir: "./dist",
  plugins: [arkenvPlugin],
});

在
bunfig.toml
中:
toml
[serve.static]
plugins = ["@arkenv/bun-plugin"]
在
Bun.build
中:
ts
import arkenvPlugin from "@arkenv/bun-plugin";

await Bun.build({
  entrypoints: ["./src/index.tsx"],
  outdir: "./dist",
  plugins: [arkenvPlugin],
});

Security Boundaries & Layouts

安全边界与布局

  • Flat layout (default):
    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.
  • Optional two-module recipe: When secret names/types must stay off the client type graph, use two modules (client + server) with two imports and optional
    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.

  • 扁平布局(默认):
    src/env.ts
    包含所有键。服务端图会在启动时执行完整验证;客户端图会获得内联的公共字面量,而访问私有服务端密钥时将抛出运行时错误。
  • 可选的双模块方案:当必须避免秘密名称或类型出现在客户端类型图中时,使用两个模块(客户端 + 服务端)、两次导入以及可选的
    extends: [clientEnv]
    。Next 可以在服务端模块中使用
    import "server-only"
    +
    @arkenv/core
    。Nuxt:绝不要从客户端代码导入服务端模块。这不是 CLI
    --strict
    标志,也不是包的
    /client
    、
    /server
    导出接口。

Best Practices & Rules

最佳实践与规则

  1. Always use
    import { env } from "./env"
    : Never use
    import.meta.env
    or
    process.env
    directly for application environment variables in v1.
  2. Never create ambient
    .d.ts
    augmentations
    :
    ImportMetaEnvAugmented
    and
    ProcessEnvAugmented
    are legacy v0 patterns dropped in v1.
  3. Keep secrets on the server: Never prefix server secrets (
    DATABASE_URL
    ,
    API_SECRET_KEY
    ) with client prefixes (
    VITE_
    ,
    NEXT_PUBLIC_
    ,
    BUN_PUBLIC_
    ,
    NUXT_PUBLIC_
    ).
  1. 始终使用
    import { env } from "./env"
    :在 v1 中,绝不要直接使用
    import.meta.env
    或
    process.env
    获取应用环境变量。
  2. 绝不创建 ambient
    .d.ts
    增强声明
    :
    ImportMetaEnvAugmented
    和
    ProcessEnvAugmented
    是已在 v1 中移除的旧版 v0 模式。
  3. 将密钥保留在服务端:绝不要使用客户端前缀(
    VITE_
    、
    NEXT_PUBLIC_
    、
    BUN_PUBLIC_
    、
    NUXT_PUBLIC_
    )标记服务端密钥(
    DATABASE_URL
    、
    API_SECRET_KEY
    )。