v1.0.0

Environment variables you can trust at runtime

Validate, secure, and manage your environment variables with full TypeScript inference. From web apps to autonomous AI agents — your config is always correct, your secrets always protected. Built on Effect Schema.

Inspired by t3-env, powered by Effect Schema.

$ bun add @ayronforge/envil effect
env.ts
import { client, createEnv, redacted, requiredString, server, shared, url } from "@ayronforge/envil"

export const appEnv = createEnv(
  shared({ APP_NAME: "My App" }),
  server({
    OPENAI_API_KEY: redacted(requiredString),
    DATABASE_URL: redacted(requiredString),
  }),
  client(
    { APP_URL: url },
    { runtimeEnv: import.meta.env, prefix: "VITE_" },
  ),
)

Everything you need

A complete toolkit for environment variable management, from schema validation to cloud secret resolution. Whether you're building a web app or an autonomous agent.

Powered by Effect Schema

Use the full power of Effect Schema for validation, transformation, and branding. Every env var gets runtime type checking with structured, parseable error messages.

Full Type Inference

Automatic TypeScript inference from your schema definitions. No manual type annotations needed — your env object is fully typed.

Guarded Runtime Boundaries

Independent Effects, typed outputs, and a defensive Proxy prevent client code from reading or materializing server values.

Framework Presets

Prefix presets for Vite, Expo, SvelteKit, and Astro compose directly with client fragment options.

Secret Manager Integrations

Resolve env vars from AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, or 1Password. Pull secrets from wherever your agents are deployed.

Composable & Extensible

Compose target-aware fragments with extendEnv, map individual variables with fromEnv or fromResolver, and keep public shared values explicit.

The runtime boundary your bundler can prove

Keep one composable environment. Envil removes server fragments from client builds, injects an exact runtime target, and keeps the Proxy as a final runtime backstop.

  • Complete server expressions are removed before the client graph is bundled.
  • Running appEnv.server in a client build fails before reading runtime values.
  • Schemas and custom resolver adapters remain ordinary runtime code.
Read the security model
import { defineConfig } from "vite"
import envil from "@ayronforge/envil/plugins/vite"

export default defineConfig({
  plugins: [envil()],
})
Vite
Rollup
webpack
esbuild
Rspack logo Rspack

Built for Autonomous Systems

AI agents run without supervision. Their environment config can't be wrong.

Fail Before You Run

Validation runs at startup, not at first use. Missing or malformed secrets crash immediately with a structured error — not halfway through a task.

Secrets That Stay Secret

redacted wraps sensitive values so they never appear in logs, traces, or agent output. Your API keys stay invisible even when agents serialize their state.

Errors Agents Can Act On

Every validation failure returns a typed, structured error with the exact variable name and reason. Agents can read what went wrong and correct course — no log parsing required.

Modular Design

Compose target-aware fragments and attach each runtime or resolver source directly to the definition that owns it.

Integrations

Resolve environment variables directly from your cloud provider's secret manager. No .env files in production.

AWS Secrets Manager

AWS Secrets Manager

import { configureResolver, createEnv, fromResolver, requiredString, server } from "@ayronforge/envil"
import { awsSecretsAdapter } from "@ayronforge/envil/aws"

const aws = configureResolver(awsSecretsAdapter, { region: "us-east-1" })

const appEnv = createEnv(
  server({
    DB_PASS: requiredString.pipe(fromResolver(aws, "prod/db-password")),
  }),
)
Azure Key Vault

Azure Key Vault

import { configureResolver, createEnv, fromResolver, requiredString, server } from "@ayronforge/envil"
import { azureKeyVaultAdapter } from "@ayronforge/envil/azure"

const azure = configureResolver(azureKeyVaultAdapter, {
  vaultUrl: "https://my-vault.vault.azure.net",
})

const appEnv = createEnv(
  server({
    DB_PASS: requiredString.pipe(fromResolver(azure, "db-password")),
  }),
)
GCP Secret Manager

GCP Secret Manager

import { configureResolver, createEnv, fromResolver, requiredString, server } from "@ayronforge/envil"
import { gcpSecretsAdapter } from "@ayronforge/envil/gcp"

const gcp = configureResolver(gcpSecretsAdapter, { projectId: "my-project" })

const appEnv = createEnv(
  server({
    DB_PASS: requiredString.pipe(fromResolver(gcp, "db-password")),
  }),
)
1Password

1Password

import { configureResolver, createEnv, fromResolver, requiredString, server } from "@ayronforge/envil"
import { onePasswordSecretsAdapter } from "@ayronforge/envil/1password"

const onePassword = configureResolver(onePasswordSecretsAdapter, {})

const appEnv = createEnv(
  server({
    DB_PASS: requiredString.pipe(
      fromResolver(onePassword, "op://vault/item/field"),
    ),
  }),
)

Framework Presets

Get started instantly with pre-configured presets for popular frameworks.

env.ts
VITE_
import { client, createEnv, requiredString, server, url } from "@ayronforge/envil"
import { vite } from "@ayronforge/envil/presets"

const appEnv = createEnv(
  server({ SECRET_KEY: requiredString }),
  client(
    { API_URL: url },
    { ...vite, runtimeEnv: import.meta.env },
  ),
)