Env
The validated, typed environment layer — the only sanctioned way to read environment variables in HaloStack.
@halostack/env is the single, sanctioned gateway to environment variables in HaloStack. It validates and types process.env exactly once at boot using envalid, then exports a frozen env object that the rest of the monorepo imports. Because the validation happens here, reading process.env directly is banned everywhere else — the one exception being the test tooling that bootstraps the environment before this package loads.
Importing
The package exposes three entry points through its exports map. Pick the subpath that matches where your code runs: server and library code gets the full schema, while the web and landing apps each get a narrower public subset so that bundling them never pulls in server-only variables.
In practice, most code reaches for the default entry point:
Structure
The package keeps schema definitions and composition separate. Each domain of configuration lives in its own schema file, and the apps/ folder assembles those schemas into the concrete env objects that consumers import.
src/schemas/holds one file per domain —base,database,auth,email,jobs,notifications,observability,sentry,storage, andapi. Each file exports avalidatormap describing its variables.src/apps/handles composition:_common.tsassembles the full server schema,packages.tsrunscleanEnvto produce the exportedenv,node-env-flags.tsderives theisProd/isDevhelpers,web.tsdefines the browser-safe subset, andlanding.tsdefines the narrow landing subset.
Adding a variable
Adding a new environment variable is a short, type-driven loop:
- Add it to the appropriate
src/schemas/<domain>.tsvalidator, supplying adevDefaultwhere it helps local development. - If the web bundle needs it, surface it explicitly in
src/apps/web.ts. - Run
bun run typecheck. Every consumer now sees the new key as a typed property.
Conventions
Never read process.env outside this package — that is the rule the whole layer exists to enforce. Note also that envalid is strictly for boot-time configuration; for untrusted application input, validate with Zod instead.