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 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_" },
),
) 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.
Use the full power of Effect Schema for validation, transformation, and branding. Every env var gets runtime type checking with structured, parseable error messages.
Automatic TypeScript inference from your schema definitions. No manual type annotations needed — your env object is fully typed.
Independent Effects, typed outputs, and a defensive Proxy prevent client code from reading or materializing server values.
Prefix presets for Vite, Expo, SvelteKit, and Astro compose directly with client fragment options.
Resolve env vars from AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, or 1Password. Pull secrets from wherever your agents are deployed.
Compose target-aware fragments with extendEnv, map individual variables with fromEnv or fromResolver, and keep public shared values explicit.
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.
appEnv.server in a client build fails before reading runtime values.
import { defineConfig } from "vite"
import envil from "@ayronforge/envil/plugins/vite"
export default defineConfig({
plugins: [envil()],
}) AI agents run without supervision. Their environment config can't be wrong.
Validation runs at startup, not at first use. Missing or malformed secrets crash immediately with a structured error — not halfway through a task.
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.
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.
Compose target-aware fragments and attach each runtime or resolver source directly to the definition that owns it.
Resolve environment variables directly from your cloud provider's secret manager. No .env files in production.
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")),
}),
) 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")),
}),
) 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")),
}),
) 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"),
),
}),
) Get started instantly with pre-configured presets for popular frameworks.
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 },
),
)