Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 25 additions & 0 deletions .changeset/large-taxis-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
"arkenv": minor
---

#### Expose `type` function

ArkEnv now exposes a `type` function with built-in ArkEnv scope, providing access to environment-specific types like `string.host` and `number.port`.

```ts
import { type } from "arkenv";

const env = type({
NODE_ENV: "string",
HOST: "string.host",
PORT: "number.port",
});

const result = env.assert({
NODE_ENV: "development",
HOST: "localhost",
PORT: "3000",
});
```

This extends ArkType's `type` function with ArkEnv-specific validations for common environment variable patterns.
275 changes: 275 additions & 0 deletions apps/www/content/docs/guides/type-function.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
---
title: "Type Function"
description: "Learn about ArkEnv's advanced type function for runtime validation with built-in environment-specific types."
---

# Type Function

> [!NOTE]
> **For most use cases, you should use the default `arkenv` export (which uses `createEnv` under the hood).** The `type` function is useful when you want to separate schema definition from validation.

> [!TIP]
> **New to ArkEnv?** Start with the [Quickstart guide](/docs/quickstart) to learn the basics with the default `arkenv` export. This guide is for when you need to separate schema definition from validation.

ArkEnv exposes a `type` function that extends ArkType's type system with environment-specific validations. This function is useful when you want to define your schema in one place and validate environment variables at a different time or location.

## Basic Usage

```ts
import { type } from "arkenv";

const env = type({
NODE_ENV: "string",
HOST: "string.host",
PORT: "number.port",
});

// Validate and transform environment variables
const result = env.assert({
NODE_ENV: "development",
HOST: "localhost",
PORT: "3000", // String input, number output
});

console.log(result);
// { NODE_ENV: "development", HOST: "localhost", PORT: 3000 }
```

## Separation of Schema Definition and Validation

The main benefit of the `type` function is that you can define your schema in one place and validate environment variables elsewhere:

```ts
// config/env-schema.ts
import { type } from "arkenv";

export const envSchema = type({
NODE_ENV: "string",
HOST: "string.host",
PORT: "number.port",
API_KEY: "string?",
});
```

```ts
// config/env.ts
import { envSchema } from "./env-schema";

// Validate environment variables using the schema
export const env = envSchema.assert(process.env);
```

```ts
// vite.config.ts
import { defineConfig } from "vite";
import arkenv from "@arkenv/vite-plugin";
import { envSchema } from "./config/env-schema";

export default defineConfig({
plugins: [arkenv(envSchema)],
});
```

This approach allows you to:
- **Reuse the same schema** across different parts of your application
- **Define schema once** and validate in multiple places
- **Keep configuration modular** and organized

## Built-in Environment Types

### `string.host`

Validates hostnames and IP addresses:

```ts
const env = type({
API_HOST: "string.host",
DB_HOST: "string.host",
});

// Valid inputs
env.assert({ API_HOST: "localhost" });
env.assert({ API_HOST: "127.0.0.1" });
env.assert({ API_HOST: "api.example.com" });

// Invalid inputs
env.assert({ API_HOST: "invalid-host" }); // ❌ Throws error
```

### `number.port`

Validates and converts port numbers:

```ts
const env = type({
PORT: "number.port",
API_PORT: "number.port",
});

// Valid inputs (strings from environment variables)
const result = env.assert({ PORT: "3000" });
console.log(result.PORT); // 3000 (number)

// Valid port range: 1-65535
env.assert({ PORT: "8080" }); // ✅ Valid
env.assert({ PORT: "65535" }); // ✅ Valid

// Invalid inputs
env.assert({ PORT: "0" }); // ❌ Too low
env.assert({ PORT: "65536" }); // ❌ Too high
env.assert({ PORT: "invalid" }); // ❌ Not a number
```

## Advanced Usage

### Optional Fields

```ts
const env = type({
REQUIRED: "string",
OPTIONAL: "string?",
PORT: "number.port?",
});

// Works with all fields
env.assert({
REQUIRED: "value",
OPTIONAL: "optional",
PORT: "3000",
});

// Works with only required fields
env.assert({
REQUIRED: "value",
// OPTIONAL and PORT are omitted
});
```

### Nested Objects

```ts
const env = type({
DATABASE: {
HOST: "string.host",
PORT: "number.port",
NAME: "string",
},
API: {
HOST: "string.host",
PORT: "number.port",
},
});

const result = env.assert({
DATABASE: {
HOST: "localhost",
PORT: "5432",
NAME: "myapp",
},
API: {
HOST: "api.example.com",
PORT: "443",
},
});
```

### Arrays

```ts
const env = type({
ALLOWED_ORIGINS: "string[]",
PORTS: "number[]",
});

const result = env.assert({
ALLOWED_ORIGINS: ["localhost", "127.0.0.1"],
PORTS: [3000, 8080, 9000],
});
```

## Error Handling

The `type` function provides detailed error messages for validation failures:

```ts
const env = type({
HOST: "string.host",
PORT: "number.port",
});

try {
env.assert({
HOST: "invalid-host",
PORT: "99999",
});
} catch (error) {
console.error(error.message);
// HOST must be a valid hostname or IP address (was "invalid-host")
// PORT must be a valid port number (was "99999")
}
```

## When to Use `type` vs `arkenv` (default export)

> [!IMPORTANT]
> **Most users should use the default `arkenv` export for environment variables.** Only use `type` when you need to separate schema definition from validation.

| Feature | `type` | `arkenv` (default) |
|---------|--------|-------------------|
| **Primary Use Case** | Schema definition separate from validation | Environment variable handling with immediate validation |
| **Input** | Any object (usually environment variables) | `process.env` or custom object |
| **Output** | Validated object | Parsed environment variables |
| **When to Use** | When you want to define schema in one file and validate in another | Environment variables (most common) |
| **Recommended for** | Advanced users, modular architecture | **Most users** |

```ts
// ✅ RECOMMENDED: Using arkenv for immediate validation
import arkenv from "arkenv";

const env = arkenv({
HOST: "string.host",
PORT: "number.port",
});

// ✅ ADVANCED: Using type to separate schema definition from validation
import { type } from "arkenv";

// Define schema in one file
const envSchema = type({
HOST: "string.host",
PORT: "number.port",
});

// Validate in another file or at a later time
const validated = envSchema.assert(process.env);
```

### Common Use Cases for `type`:

- **Modular Architecture**: Define schema in a shared config file, validate in different modules
- **Delayed Validation**: Define schema early but validate environment variables later in your application lifecycle
- **Schema Reuse**: Use the same schema definition for different validation scenarios
- **Testing**: Define schema once and use it for testing different environment configurations

## Integration with Vite

The `type` function works seamlessly with the Vite plugin:

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

const envSchema = type({
VITE_API_URL: "string",
VITE_HOST: "string.host",
VITE_PORT: "number.port",
});

export default defineConfig({
plugins: [arkenv(envSchema)],
});
```

This ensures your environment variables are validated at build time with the same type definitions you use for runtime validation.
1 change: 1 addition & 0 deletions apps/www/content/docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ ArkEnv is a powerful TypeScript-first environment variable management library th
- 🔒 **Typesafe**: Full TypeScript support with precise type inference
- 🚀 **Runtime validation**: Catch missing or invalid environment variables early in development
- 💪 **Powered by ArkType**: Built on top of ArkType's powerful type system
- 🛠️ **Type function**: Use `type()` to separate schema definition from validation
- 🪶 **Lightweight**: Only a single dependency ([see size](https://bundlephobia.com/package/arkenv))
- ⚡ **Fast**: Optimized for performance with minimal overhead

Expand Down
1 change: 1 addition & 0 deletions apps/www/content/docs/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"examples",
"---Guides---",
"guides/import-options",
"guides/type-function",
"guides/environment-configuration"
]
}
5 changes: 5 additions & 0 deletions apps/www/content/docs/quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ description: Let's get you started with a few simple steps
href="/docs/guides/import-options"
description="Get syntax highlighting and enhanced developer experience with the ArkType VS Code extension"
/>
<Card
title="Type Function"
href="/docs/guides/type-function"
description="Learn how to separate schema definition from validation using ArkEnv's type function"
/>
<Card
title="Loading environment variables"
href="/docs/guides/environment-configuration"
Expand Down
4 changes: 1 addition & 3 deletions packages/arkenv/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
// Type exports
export type { EnvSchema } from "./create-env";
// Named exports
export * from "./create-env";
// Export createEnv as the main default export
export { createEnv as default } from "./create-env";
export * from "./type";
Loading
Loading