Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
a8f5f61
docs(validator): add explicit mode design docs
yamcodes Jan 14, 2026
1201d6f
docs(design): add non-goals for validator mode
yamcodes Jan 14, 2026
213fe31
feat: Refine and expand the task list for explicit validator mode imp…
yamcodes Jan 14, 2026
6ba7322
docs: Refine design document for explicit validator mode, detailing A…
yamcodes Jan 14, 2026
a35a74e
feat: add requirements for explicit error handling in standard valida…
yamcodes Jan 14, 2026
22abf0b
feat: Add explicit `validator` mode to `ArkEnvConfig` for `arktype` o…
yamcodes Jan 14, 2026
3ff8a01
docs: detail the design for an explicit `validator` option in `create…
yamcodes Jan 14, 2026
e8bfac8
feat: Refine `standard` validator mode specification by clarifying co…
yamcodes Jan 14, 2026
5f1dcc9
feat: Dynamically show send button and prevent sending empty or compo…
yamcodes Jan 14, 2026
d8e3e5c
Refine the explicit validator mode proposal by clarifying its rationa…
yamcodes Jan 15, 2026
03e5549
Merge branch 'main' into 722-make-arktype-optional-and-use-standard-s…
yamcodes Jan 15, 2026
b5decc8
feat: introduce explicit validator mode
yamcodes Jan 15, 2026
2638105
refactor: separate `indent` and `styleText` utilities into individual…
yamcodes Jan 15, 2026
54200f3
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 15, 2026
3ee8017
feat: implement explicit validator mode with dispatcher, refactor Ark…
yamcodes Jan 15, 2026
98e35e4
refactor: Extract ArkType scope definitions into variables and adjust…
yamcodes Jan 15, 2026
dd0dc95
refactor: Refine ArkType proxy to use `$.type` for type access and ad…
yamcodes Jan 15, 2026
c787cef
fix: Correctly identify ArkType errors using `isArkErrors` and enhanc…
yamcodes Jan 15, 2026
f747089
feat: Complete implementation tasks for the explicit validator mode, …
yamcodes Jan 15, 2026
4578bfa
feat: Implement lazy loading for ArkType and its scope/keywords to im…
yamcodes Jan 15, 2026
88ae425
refactor: rename `lazyKeyword` to `keyword` and refine its type signa…
yamcodes Jan 15, 2026
541b50d
feat: Make ArkType an optional peer dependency and refactor internal …
yamcodes Jan 15, 2026
25495fc
feat: Integrate ArkType custom scope keywords directly into Arkenv, r…
yamcodes Jan 15, 2026
8d10fa2
feat: add `without-arktype` example and enhance `with-standard-schema…
yamcodes Jan 15, 2026
f0aadd0
chore: Add 'without-arktype' example folder to the workspace configur…
yamcodes Jan 15, 2026
1b6c9ad
Modify `HOST` environment variable definition to accept IP addresses …
yamcodes Jan 15, 2026
ac7bd40
refactor: Standardize schema examples to use Zod exclusively and upda…
yamcodes Jan 15, 2026
72a8cdd
feat: Enhance environment variable parsing by using `z.coerce.number(…
yamcodes Jan 15, 2026
c5541df
chore: Add `validator: "standard"` option to the `createEnv` function…
yamcodes Jan 15, 2026
62baf37
deps: update arkenv dependency version.
yamcodes Jan 15, 2026
10ec95e
docs: Rephrase explicit non-goals for improved clarity and prescripti…
yamcodes Jan 15, 2026
f6be7fe
refactor: remove `StandardValidator` type and update `parseStandard` …
yamcodes Jan 15, 2026
253c1c5
feat: Add standard-schema types and a Dict helper, and refine arktype…
yamcodes Jan 15, 2026
c5bf4dc
feat: enhance `InferType` to support `{ t: U }` pattern and utilize `…
yamcodes Jan 15, 2026
df54547
refactor: update type import from `arktype` to `@repo/scope`'s `$` ob…
yamcodes Jan 15, 2026
5076970
refactor(arkenv): Use shared StandardSchemaV1 type
yamcodes Jan 15, 2026
03c5732
refactor: Reorder conditional types in `InferType` to prioritize func…
yamcodes Jan 16, 2026
8262d4f
Merge branch 'main' into 722-make-arktype-optional-and-use-standard-s…
yamcodes Jan 16, 2026
54d5c19
docs: update reported bundle size
yamcodes Jan 16, 2026
4954c2e
feat(types): add standard schema and helpers
yamcodes Jan 16, 2026
e2e2975
feat(arkenv): make ArkType optional with new validator option
yamcodes Jan 16, 2026
275dc1a
docs(arkenv): enhance coercion and installation instructions
yamcodes Jan 16, 2026
a99bd2f
docs(arkenv): streamline Standard Schema documentation
yamcodes Jan 16, 2026
e81ff0e
Merge branch 'main' into 722-make-arktype-optional-and-use-standard-s…
yamcodes Jan 16, 2026
2e237d6
feat: Make ArkType an optional dependency by dynamically loading it a…
yamcodes Jan 16, 2026
e921685
chore: Reorder imports for consistency across several files.
yamcodes Jan 16, 2026
341edb0
refactor: move schema definition logic to a separate `arkenv/arktype`…
yamcodes Jan 16, 2026
1bc4c6a
chore: Refine vite-plugin Vitest alias resolution for `arkenv` and `a…
yamcodes Jan 16, 2026
1f7a26f
chore: Reordered `@repo/types` and `@repo/scope` in `devDependencies`.
yamcodes Jan 16, 2026
f858f6c
feat: Make ArkType an optional peer dependency, move the `type` expor…
yamcodes Jan 16, 2026
1595a53
docs: Clarify that helpers imported from `arkenv/arktype` are 'ArkTyp…
yamcodes Jan 16, 2026
da5dcc5
docs: Separate arkenv and arktype imports in the vite config example.
yamcodes Jan 16, 2026
ed40bdf
refactor: Remove keywords export from the scope package.
yamcodes Jan 16, 2026
e0c5048
Remove `@types/node` dependency and its TypeScript configuration, alo…
yamcodes Jan 16, 2026
842feca
refactor: update `type` import path to `arkenv/arktype` in example co…
yamcodes Jan 16, 2026
ba7ff43
feat: add CommonJS search paths for arktype module loading
yamcodes Jan 16, 2026
089a3b4
feat: add runtime validation for Standard Schema in createEnv function
yamcodes Jan 16, 2026
ca51f08
fix: update PORT and DEBUG validation to use coercion in standard schema
yamcodes Jan 16, 2026
b3def59
fix: use coercion for PORT validation in standard schema
yamcodes Jan 16, 2026
aa1b9b9
feat: introduce and document validator mode, clarifying coercion and …
yamcodes Jan 16, 2026
b71e26c
feat: Add documentation for ArkEnv's `arktype` and `standard` validat…
yamcodes Jan 16, 2026
93c4b17
fix: Update internal documentation links to use absolute paths.
yamcodes Jan 16, 2026
57d66e7
docs: add note on ArkType usage in quickstart and update IDE integrat…
yamcodes Jan 16, 2026
7b6936e
feat: Add ArkType-based type coercion for environment variables, supp…
yamcodes Jan 16, 2026
c2e50b0
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 16, 2026
3affdf6
docs: Update ArkType mode hyphenation and validator mode icon.
yamcodes Jan 16, 2026
3a57eab
docs: Remove 'New' icon from validator-mode MDX and update its naviga…
yamcodes Jan 16, 2026
288df49
refactor: remove arktype dependency and switch to standard validator …
yamcodes Jan 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .changeset/every-tips-shout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
"arkenv": minor
---

#### ArkType is now an optional peer dependency

To achieve a true zero-dependency core, ArkType is now an optional peer dependency.

- **Breaking Change**: The `type` export has been moved from the main `arkenv` entry point to `arkenv/arktype`.

```ts
// ❌ Before
import { type } from "arkenv";

// ✅ After
import { type } from "arkenv/arktype";
```

- **Explicit Validator Modes**: ArkEnv now supports an explicit `validator` option.

- **`validator: "arktype"` (default)**: Uses ArkType for validation and coercion. Requires `arktype` to be installed.
- **`validator: "standard"`**: Uses Standard Schema validators directly (e.g., Zod, Valibot). Works without ArkType.

Existing usage of `arkenv()` remains unchanged when ArkType is installed. Projects using ArkType features must now explicitly install `arktype` and import ArkType-land helpers from `arkenv/arktype`.
5 changes: 5 additions & 0 deletions .changeset/tender-books-shout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@repo/types": patch
---

#### Added Standard Schema, helpers
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ coverage/
esbuild-why*.html

# arktype clone
arktype/
/arktype/

# explicitly ignored folder
ignore-me/
2 changes: 1 addition & 1 deletion apps/playgrounds/bun-react/src/env.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type } from "arkenv";
import { type } from "arkenv/arktype";

export default type({
BUN_PUBLIC_API_URL: "string.url",
Expand Down
2 changes: 1 addition & 1 deletion apps/playgrounds/solid-start/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ The example uses a single schema definition in `app.config.ts` that defines the
```ts title="app.config.ts"
import arkenvVitePlugin from "@arkenv/vite-plugin";
import { defineConfig } from "@solidjs/start/config";
import { type } from "arkenv";
import { type } from "arkenv/arktype";

// Define the schema
export const Env = type({
Expand Down
2 changes: 1 addition & 1 deletion apps/playgrounds/solid-start/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import arkenvVitePlugin from "@arkenv/vite-plugin";
import { defineConfig } from "@solidjs/start/config";
import { type } from "arkenv";
import { type } from "arkenv/arktype";

export const Env = type({
VITE_TEST: "string",
Expand Down
55 changes: 27 additions & 28 deletions apps/playgrounds/standard-schema/index.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,45 @@
import arkenv, { type } from "arkenv";
import arkenv from "arkenv";
import * as z from "zod";

const env = arkenv({
// ArkType validators (concise TypeScript-like syntax)
HOST: "string.host",
PORT: "number.port",
NODE_ENV: "'development' | 'production' | 'test' = 'development'",
DEBUG: "boolean = false",
const env = arkenv(
{
// Zod validators (great for complex validation and transformations)
DATABASE_URL: z.string().url(),
API_KEY: z
.string()
.min(32)
.describe("API key must be at least 32 characters"),

// Zod validators (great for complex validation and transformations)
DATABASE_URL: z.url(),
API_KEY: z
.string()
.min(32)
.describe("API key must be at least 32 characters"),
// Standard Schema compatible validators
MAX_RETRIES: z.coerce.number().int().positive().default(3),
TIMEOUT_MS: z.coerce.number().int().min(0).max(30000).default(5000),

// Mix them together based on your needs
MAX_RETRIES: z.number().int().positive().default(3),
TIMEOUT_MS: z.number().int().min(0).max(30000).default(5000),
// Complex transformations with Zod
ALLOWED_ORIGINS: z
.string()
.transform((str: string) => str.split(","))
.pipe(z.array(z.string().url())),

// Complex transformations with Zod
ALLOWED_ORIGINS: z
.string()
.transform((str: string) => str.split(","))
.pipe(z.array(z.url())),

// Array defaults with ArkType
FEATURE_FLAGS: type("string[]").default(() => []),
});
NODE_ENV: z
.enum(["development", "production", "test"])
.default("development"),
DEBUG: z
.union([z.boolean(), z.enum(["true", "false", "1", "0"])])
.transform((v) => v === true || v === "true" || v === "1")
.default(false),
},
{ validator: "standard" },
);

// All validators work together seamlessly with full type inference
console.log({
host: env.HOST,
port: env.PORT,
nodeEnv: env.NODE_ENV,
debug: env.DEBUG,
databaseUrl: env.DATABASE_URL,
apiKey: `${env.API_KEY.substring(0, 8)}...`, // Don't log full API key
maxRetries: env.MAX_RETRIES,
timeoutMs: env.TIMEOUT_MS,
allowedOrigins: env.ALLOWED_ORIGINS,
featureFlags: env.FEATURE_FLAGS,
});

export default env;
3 changes: 2 additions & 1 deletion apps/playgrounds/vite-legacy/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import arkenvVitePlugin from "@arkenv/vite-plugin";
import reactPlugin from "@vitejs/plugin-react";
import arkenv, { type } from "arkenv";
import arkenv from "arkenv";
import { type } from "arkenv/arktype";
import { defineConfig, loadEnv } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";

Expand Down
2 changes: 1 addition & 1 deletion apps/playgrounds/vite/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ The example uses a single schema definition that's reused for both server-side c

```ts title="vite.config.ts"
import arkenvVitePlugin from "@arkenv/vite-plugin";
import arkenv, { type } from "arkenv";
import arkenv from "arkenv"; import { type } from "arkenv/arktype";
import { defineConfig, loadEnv } from "vite";

// Define the schema once
Expand Down
3 changes: 2 additions & 1 deletion apps/playgrounds/vite/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import arkenvVitePlugin from "@arkenv/vite-plugin";
import reactPlugin from "@vitejs/plugin-react";
import arkenv, { type } from "arkenv";
import arkenv from "arkenv";
import { type } from "arkenv/arktype";
import { defineConfig, loadEnv } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";

Expand Down
4 changes: 3 additions & 1 deletion apps/www/content/docs/arkenv/coercion.mdx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
---
title: Coercion
description: Environment variables are auto-morphed into typesafe numbers, booleans, and more.
icon: Updated
---

Traditionally, environment variables are always strings by default. ArkEnv **coerces** these strings into their target types based on your schema, so you only have to think about the types you want.

> [!IMPORTANT]
> Coercion is only available in **ArkType mode** (the default). When using `validator: "standard"`, your Standard Schema validators handle their own parsing and type conversion.

## Numbers

Any field defined as a `number` or a numeric subtype (like `number.integer` or `number.port`) will be automatically parsed.
Expand Down
105 changes: 105 additions & 0 deletions apps/www/content/docs/arkenv/how-to/load-environment-variables.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,111 @@ export const env = arkenv({
});
```

## Configuration options

ArkEnv supports several configuration options to customize its behavior:

### Validator mode

Choose between ArkType (default) or Standard Schema validators:

```typescript title="src/config/env.ts" twoslash
import arkenv from 'arkenv';
import { z } from 'zod';

// ArkType mode (default) - requires ArkType to be installed
const env1 = arkenv({
PORT: "number.port",
HOST: "string.host",
});

// Standard mode - works without ArkType
const env2 = arkenv(
{
PORT: z.coerce.number().int().min(0).max(65535),
DATABASE_URL: z.string().url(),
},
{ validator: "standard" }
);
```

### Coercion

Control automatic type conversion (only available in ArkType mode):

```typescript title="src/config/env.ts" twoslash
import arkenv from 'arkenv';

// Coercion enabled (default)
const env1 = arkenv({
PORT: "number.port", // "3000" becomes 3000
});

// Coercion disabled
const env2 = arkenv(
{
PORT: "number.port",
},
{ coerce: false } // Must be a number; strings (like those from process.env) will fail
);
```

> [!NOTE]
> Since `process.env` values are always strings, using `coerce: false` with numeric or boolean schemas will cause validation to fail unless you provide a custom `env` source containing the expected literal types.
```

### Custom environment source

Provide a custom environment object:

```typescript title="src/config/env.ts" twoslash
import arkenv from 'arkenv';

const env = arkenv(
{
PORT: "number.port",
},
{
env: {
PORT: "3000",
// ... other variables
},
}
);
```

### Array format

Control how arrays are parsed (only available in ArkType mode):

```typescript title="src/config/env.ts" twoslash
import arkenv from 'arkenv';

// Comma-separated (default)
const env1 = arkenv(
{
TAGS: "string[]",
},
{
env: { TAGS: "web, app, api" },
arrayFormat: "comma",
}
);

// JSON format
const env2 = arkenv(
{
TAGS: "string[]",
},
{
env: { TAGS: '["web", "app"]' },
arrayFormat: "json",
}
);
```

For more details on configuration options, see the [coercion documentation](/docs/arkenv/coercion) and [Standard Schema integration guide](/docs/arkenv/integrations/standard-schema).

## Common patterns

### Configuration factory
Expand Down
3 changes: 2 additions & 1 deletion apps/www/content/docs/arkenv/how-to/reuse-schemas.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ This might sound like a niche use-case, but it comes up more often than you'd th
That's where type definitions start making sense: define your schema once with `type()`, and reuse it wherever you need.

```ts twoslash
import arkenv, { type } from 'arkenv';
import arkenv from 'arkenv';
import { type } from 'arkenv/arktype';

const Env = type({
HOST: "string.host",
Expand Down
2 changes: 1 addition & 1 deletion apps/www/content/docs/arkenv/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ We consider the resulting `env` object "typesafe from editor to runtime": at eve

### Editor

ArkEnv tells TypeScript about the shape of your environment variables, so you can use the types your schema defines without additional checks or manual type-casts. Your editor will also autocomplete your schema and provide type hints, whether you're using [ArkType](https://arktype.io/), Zod, Valibot, or any other Standard Schema validator. If you're using ArkType, you can take this a step further with [syntax highlighting and inline errors](docs/arkenv/integrations/vscode). This way, writing your schema feels like writing TypeScript.
ArkEnv tells TypeScript about the shape of your environment variables, so you can use the types your schema defines without additional checks or manual type-casts. Your editor will also autocomplete your schema and provide type hints, whether you're using [ArkType](https://arktype.io/), Zod, Valibot, or any other Standard Schema validator. If you're using ArkType, you can take this a step further with [syntax highlighting and inline errors](/docs/arkenv/integrations/vscode). This way, writing your schema feels like writing TypeScript.

### Build time

Expand Down
Loading
Loading